home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / normal.c < prev    next >
C/C++ Source or Header  |  1996-06-17  |  79KB  |  3,460 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * Contains the main routine for processing characters in command mode.
  11.  * Communicates closely with the code in ops.c to handle the operators.
  12.  */
  13.  
  14. #include "vim.h"
  15. #include "globals.h"
  16. #include "proto.h"
  17. #include "option.h"
  18.  
  19. #undef EXTERN
  20. #undef INIT
  21. #define EXTERN
  22. #define INIT(x) x
  23. #include "ops.h"
  24.  
  25. /*
  26.  * Generally speaking, every command in normal() should either clear any
  27.  * pending operator (with clearop()), or set the motion type variable.
  28.  */
  29.  
  30. /*
  31.  * If a count is given before the operator, it is saved in opnum.
  32.  */
  33. static linenr_t    opnum = 0;
  34. static linenr_t    Prenum;         /* The (optional) number before a command. */
  35. static int        prechar = NUL;    /* prepended command char */
  36. /*
  37.  * The visual area is remembered for reselection.
  38.  */
  39. static int        resel_VIsual_mode = NUL;    /* 'v', 'V', or Ctrl-V */
  40. static linenr_t    resel_VIsual_line_count;        /* number of lines */
  41. static colnr_t    resel_VIsual_col;            /* number of cols or end column */
  42.  
  43. #ifdef USE_MOUSE
  44. static void        find_start_of_word __ARGS((FPOS *));
  45. static void        find_end_of_word __ARGS((FPOS *));
  46. static int        get_mouse_class __ARGS((int));
  47. #endif
  48. static void        prep_redo __ARGS((long, int, int, int, int));
  49. static int        checkclearop __ARGS((void));
  50. static int        checkclearopq __ARGS((void));
  51. static void        clearop __ARGS((void));
  52. static void        clearopbeep __ARGS((void));
  53. static void        del_from_showcmd __ARGS((int));
  54. static void        do_gd __ARGS((int nchar));
  55.  
  56. /*
  57.  * normal
  58.  *
  59.  * Execute a command in normal mode.
  60.  *
  61.  * This is basically a big switch with the cases arranged in rough categories
  62.  * in the following order:
  63.  *
  64.  *      0. Macros (q, @)
  65.  *      1. Screen positioning commands (^U, ^D, ^F, ^B, ^E, ^Y, z)
  66.  *      2. Control commands (:, <help>, ^L, ^G, ^^, ZZ, *, ^], ^T)
  67.  *      3. Cursor motions (G, H, M, L, l, K_RIGHT,  , h, K_LEFT, ^H, k, K_UP,
  68.  *         ^P, +, CR, LF, j, K_DOWN, ^N, _, |, B, b, W, w, E, e, $, ^, 0)
  69.  *      4. Searches (?, /, n, N, T, t, F, f, ,, ;, ], [, %, (, ), {, })
  70.  *      5. Edits (., u, K_UNDO, ^R, U, r, J, p, P, ^A, ^S)
  71.  *      6. Inserts (A, a, I, i, o, O, R)
  72.  *      7. Operators (~, d, c, y, >, <, !, =, Q)
  73.  *      8. Abbreviations (x, X, D, C, s, S, Y, &)
  74.  *      9. Marks (m, ', `, ^O, ^I)
  75.  *     10. Buffer setting (")
  76.  *     11. Visual (v, V, ^V)
  77.  *   12. Suspend (^Z)
  78.  *   13. Window commands (^W)
  79.  *   14. extended commands (starting with 'g')
  80.  *   15. mouse click
  81.  *   16. scrollbar movement
  82.  *   17. The end (ESC)
  83.  */
  84.  
  85.     void
  86. normal()
  87. {
  88.     register int    c;
  89.     long             n = 0;                    /* init for GCC */
  90.     int                flag = FALSE;
  91.     int                flag2 = FALSE;
  92.     int             type = 0;                /* type of operation */
  93.     int             dir = FORWARD;            /* search direction */
  94.     int                nchar = NUL;            /* next command char */
  95.     int                finish_op;
  96.     linenr_t        Prenum1;
  97.     char_u            *searchbuff = NULL;        /* buffer for search string */
  98.     FPOS            *pos = NULL;            /* init for gcc */
  99.     char_u            *ptr = NULL;
  100.     int                command_busy = FALSE;
  101.     int                ctrl_w = FALSE;            /* got CTRL-W command */
  102.     int                old_col = 0;
  103.     int                dont_adjust_op_end = FALSE;
  104.  
  105.     Prenum = 0;
  106.     /*
  107.      * If there is an operator pending, then the command we take this time
  108.      * will terminate it. Finish_op tells us to finish the operation before
  109.      * returning this time (unless the operation was cancelled).
  110.      */
  111.     finish_op = (op_type != NOP);
  112.  
  113.     if (!finish_op && !yankbuffer)
  114.         opnum = 0;
  115.  
  116.     State = NORMAL_BUSY;
  117.     c = vgetc();
  118. #ifdef HAVE_LANGMAP
  119.     LANGMAP_ADJUST(c, TRUE);
  120. #endif
  121.     if (c == NUL)
  122.         c = K_ZERO;
  123.     (void)add_to_showcmd(c, FALSE);
  124.  
  125. getcount:
  126.     /* Pick up any leading digits and compute 'Prenum' */
  127.     while ((c >= '1' && c <= '9') || (Prenum != 0 && (c == K_DEL || c == '0')))
  128.     {
  129.         if (c == K_DEL)
  130.         {
  131.             Prenum /= 10;
  132.             del_from_showcmd(4);        /* delete the digit and ~@% */
  133.         }
  134.         else
  135.             Prenum = Prenum * 10 + (c - '0');
  136.         if (Prenum < 0)            /* got too large! */
  137.             Prenum = 999999999;
  138.         c = vgetc();
  139. #ifdef HAVE_LANGMAP
  140.         LANGMAP_ADJUST(c, TRUE);
  141. #endif
  142.         (void)add_to_showcmd(c, FALSE);
  143.     }
  144.  
  145. /*
  146.  * If we got CTRL-W there may be a/another count
  147.  */
  148.     if (c == Ctrl('W') && !ctrl_w && op_type == NOP)
  149.     {
  150.         ctrl_w = TRUE;
  151.         opnum = Prenum;                        /* remember first count */
  152.         Prenum = 0;
  153.         ++no_mapping;
  154.         ++allow_keys;                        /* no mapping for nchar, but keys */
  155.         c = vgetc();                        /* get next character */
  156. #ifdef HAVE_LANGMAP
  157.         LANGMAP_ADJUST(c, TRUE);
  158. #endif
  159.         --no_mapping;
  160.         --allow_keys;
  161.         (void)add_to_showcmd(c, FALSE);
  162.         goto getcount;                        /* jump back */
  163.     }
  164.  
  165.     /*
  166.      * If we're in the middle of an operator (including after entering a yank
  167.      * buffer with ") AND we had a count before the
  168.      * operator, then that count overrides the current value of Prenum. What
  169.      * this means effectively, is that commands like "3dw" get turned into
  170.      * "d3w" which makes things fall into place pretty neatly.
  171.      * If you give a count before AND after the operator, they are multiplied.
  172.      */
  173.     if (opnum != 0)
  174.     {
  175.             if (Prenum)
  176.                 Prenum *= opnum;
  177.             else
  178.                 Prenum = opnum;
  179.             opnum = 0;
  180.     }
  181.  
  182.     Prenum1 = (Prenum == 0 ? 1 : Prenum);        /* Prenum often defaults to 1 */
  183.  
  184.     /*
  185.      * Get an additional character if we need one.
  186.      * For CTRL-W we already got it when looking for a count.
  187.      */
  188.     if (ctrl_w)
  189.     {
  190.         nchar = c;
  191.         c = Ctrl('W');
  192.     }
  193.     else if ((op_type == NOP && vim_strchr((char_u *)"@zm\"", c) != NULL) ||
  194.             (op_type == NOP && !VIsual_active &&
  195.                  vim_strchr((char_u *)"rZ", c) != NULL) ||
  196.             vim_strchr((char_u *)"tTfF[]g'`", c) != NULL ||
  197.             (c == 'q' && !Recording && !Exec_reg))
  198.     {
  199.         ++no_mapping;
  200.         ++allow_keys;            /* no mapping for nchar, but allow key codes */
  201.         nchar = vgetc();
  202. #ifdef HAVE_LANGMAP
  203.         /* adjust chars > 127: tTfFr should leave lang of nchar unchanged! */
  204.         LANGMAP_ADJUST(nchar, vim_strchr((char_u *)"tTfFr", c) == NULL);
  205. #endif
  206. #ifdef RIGHTLEFT
  207.         if (p_hkmap && strchr("tTfFr", c) && KeyTyped)     /* Hebrew mapped char */
  208.             nchar = hkmap(nchar);
  209. #endif
  210.         --no_mapping;
  211.         --allow_keys;
  212.         (void)add_to_showcmd(nchar, FALSE);
  213.     }
  214.     if (p_sc)
  215.         flushbuf();                /* flush the showcmd characters onto the
  216.                                  * screen so we can see them while the command
  217.                                  * is being executed
  218.                                  */
  219.  
  220.     State = NORMAL;
  221.     if (nchar == ESC)
  222.     {
  223.         clearop();
  224.         goto normal_end;
  225.     }
  226.     msg_didout = FALSE;        /* don't scroll screen up for normal command */
  227.     msg_col = 0;
  228.  
  229. #ifdef RIGHTLEFT
  230.     if (curwin->w_p_rl && KeyTyped)        /* invert horizontal operations */
  231.         switch (c)
  232.         {
  233.             case 'l':       c = 'h'; break;
  234.             case K_RIGHT:    c = K_LEFT; break;
  235.             case 'h':        c = 'l'; break;
  236.             case K_LEFT:    c = K_RIGHT; break;
  237.             case '>':        c = '<'; break;
  238.             case '<':        c = '>'; break;
  239.         }
  240. #endif
  241.     switch (c)
  242.     {
  243.  
  244. /*
  245.  * 0: Macros
  246.  */
  247.       case 'q':         /* (stop) recording into a named register */
  248.         if (checkclearop())
  249.             break;
  250.                         /* command is ignored while executing a register */
  251.         if (!Exec_reg && do_record(nchar) == FAIL)
  252.             clearopbeep();
  253.         break;
  254.  
  255.      case '@':            /* execute a named buffer */
  256.         if (checkclearop())
  257.             break;
  258.         while (Prenum1--)
  259.         {
  260.             if (do_execbuf(nchar, FALSE, FALSE) == FAIL)
  261.             {
  262.                 clearopbeep();
  263.                 break;
  264.             }
  265.         }
  266.         break;
  267.  
  268. /*
  269.  * 1: Screen positioning commands
  270.  */
  271.       case Ctrl('D'):
  272.         flag = TRUE;
  273.  
  274.       case Ctrl('U'):
  275.         if ((c == Ctrl('U') && curwin->w_cursor.lnum == 1) ||
  276.             (c == Ctrl('D') && curwin->w_cursor.lnum ==
  277.                                                   curbuf->b_ml.ml_line_count))
  278.                 clearopbeep();
  279.         else
  280.         {
  281.             if (checkclearop())
  282.                 break;
  283.             halfpage(flag, Prenum);
  284.         }
  285.         break;
  286.  
  287.       case Ctrl('B'):
  288.       case K_S_UP:
  289.       case K_PAGEUP:
  290.         dir = BACKWARD;
  291.  
  292.       case Ctrl('F'):
  293.       case K_S_DOWN:
  294.       case K_PAGEDOWN:
  295.         if (checkclearop())
  296.             break;
  297.         (void)onepage(dir, Prenum1);
  298.         break;
  299.  
  300.       case Ctrl('E'):
  301.         if (checkclearop())
  302.             break;
  303.         scrollup(Prenum1);
  304.         if (p_so)
  305.             cursor_correct();
  306.         /* We may have moved to another line -- webb */
  307.         coladvance(curwin->w_curswant);
  308.         cursupdate();
  309.         updateScreen(VALID);
  310.         break;
  311.  
  312.       case Ctrl('Y'):
  313.         if (checkclearop())
  314.             break;
  315.         scrolldown(Prenum1);
  316.         if (p_so)
  317.             cursor_correct();
  318.         /* We may have moved to another line -- webb */
  319.         coladvance(curwin->w_curswant);
  320.         updateScreen(VALID);
  321.         break;
  322.  
  323.       case 'z':
  324.         if (checkclearop())
  325.             break;
  326.         if (nchar < 0x100 && isdigit(nchar))
  327.         {
  328.             Prenum = nchar - '0';
  329.             for (;;)
  330.             {
  331.                 ++no_mapping;
  332.                 ++allow_keys;    /* no mapping for nchar, but allow key codes */
  333.                 nchar = vgetc();
  334. #ifdef HAVE_LANGMAP
  335.                 LANGMAP_ADJUST(c, TRUE);
  336. #endif
  337.                 --no_mapping;
  338.                 --allow_keys;
  339.                 (void)add_to_showcmd(nchar, FALSE);
  340.                 if (c == K_DEL)
  341.                     Prenum /= 10;
  342.                 else if (nchar < 0x100 && isdigit(nchar))
  343.                     Prenum = Prenum * 10 + (nchar - '0');
  344.                 else if (nchar == CR)
  345.                 {
  346.                     win_setheight((int)Prenum);
  347.                     break;
  348.                 }
  349.                 else if (nchar == 'l' || nchar == 'h' ||
  350.                                           nchar == K_LEFT || nchar == K_RIGHT)
  351.                 {
  352.                     Prenum1 = Prenum ? Prenum : 1;
  353.                     goto dozet;
  354.                 }
  355.                 else
  356.                 {
  357.                     clearopbeep();
  358.                     break;
  359.                 }
  360.             }
  361.             op_type = NOP;
  362.             break;
  363.         }
  364. dozet:
  365.         /*
  366.          * If line number given, set cursor, except for "zh", "zl", "ze" and
  367.          * "zs"
  368.          */
  369.         if (vim_strchr((char_u *)"hles", nchar) == NULL &&
  370.                                         nchar != K_LEFT && nchar != K_RIGHT &&
  371.                                     Prenum && Prenum != curwin->w_cursor.lnum)
  372.         {
  373.             setpcmark();
  374.             if (Prenum > curbuf->b_ml.ml_line_count)
  375.                 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  376.             else
  377.                 curwin->w_cursor.lnum = Prenum;
  378.         }
  379.         switch (nchar)
  380.         {
  381.           case NL:                /* put curwin->w_cursor at top of screen */
  382.           case CR:
  383.             beginline(TRUE);
  384.             /* FALLTHROUGH */
  385.           case 't':
  386.             scroll_cursor_top(0, TRUE);
  387.             break;
  388.  
  389.           case '.':             /* put curwin->w_cursor in middle of screen */
  390.             beginline(TRUE);
  391.             /* FALLTHROUGH */
  392.           case 'z':
  393.             scroll_cursor_halfway(TRUE);
  394.             break;
  395.  
  396.           case '-':             /* put curwin->w_cursor at bottom of screen */
  397.             beginline(TRUE);
  398.             /* FALLTHROUGH */
  399.           case 'b':
  400.             scroll_cursor_bot(0, TRUE);
  401.             break;
  402.  
  403.             /* "zh" - scroll screen to the right */
  404.           case 'h':
  405.           case K_LEFT:
  406.             if (!curwin->w_p_wrap)
  407.             {
  408.                 colnr_t        s, e;
  409.  
  410.                 if ((colnr_t)Prenum1 > curwin->w_leftcol)
  411.                     curwin->w_leftcol = 0;
  412.                 else
  413.                     curwin->w_leftcol -= (colnr_t)Prenum1;
  414.                 n = curwin->w_leftcol + Columns -
  415.                     (curwin->w_p_nu ? 8 : 0) - 1;
  416.                 if (curwin->w_virtcol > (colnr_t)n)
  417.                     coladvance((colnr_t)n);
  418.  
  419.                 getvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
  420.                 if (e > (colnr_t)n)
  421.                     coladvance(s - 1);
  422.                 redraw_later(NOT_VALID);
  423.             }
  424.             break;
  425.  
  426.             /* "zl" - scroll screen to the left */
  427.           case 'l':
  428.           case K_RIGHT:
  429.             if (!curwin->w_p_wrap)
  430.             {
  431.                 colnr_t        s, e;
  432.  
  433.                 /* scroll the window left */
  434.                 curwin->w_leftcol += (colnr_t)Prenum1;
  435.  
  436.                 /* If the cursor has moved off the screen, put it at the
  437.                  * first char on the screen */
  438.                 if (curwin->w_leftcol > curwin->w_virtcol)
  439.                     (void)coladvance(curwin->w_leftcol);
  440.  
  441.                 /* If the start of the character under the cursor is not
  442.                  * on the screen, advance the cursor one more char.  If
  443.                  * this fails (last char of the line) adjust the
  444.                  * scrolling. */
  445.                 getvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
  446.                 if (s < curwin->w_leftcol)
  447.                     if (coladvance(e + 1) == FAIL)
  448.                         curwin->w_leftcol = s;
  449.  
  450.                 redraw_later(NOT_VALID);
  451.             }
  452.             break;
  453.  
  454.             /* "zs" - scroll screen, cursor at the start */
  455.           case 's':
  456.             if (!curwin->w_p_wrap)
  457.             {
  458.                 colnr_t        s;
  459.  
  460.                 getvcol(curwin, &curwin->w_cursor, &s, NULL, NULL);
  461.                 curwin->w_leftcol = s;
  462.                 redraw_later(NOT_VALID);
  463.             }
  464.             break;
  465.  
  466.             /* "ze" - scroll screen, cursor at the end */
  467.           case 'e':
  468.             if (!curwin->w_p_wrap)
  469.             {
  470.                 colnr_t        e;
  471.  
  472.                 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &e);
  473.                 if ((long)e < Columns)
  474.                     curwin->w_leftcol = 0;
  475.                 else
  476.                     curwin->w_leftcol = e - Columns + 1;
  477.                 redraw_later(NOT_VALID);
  478.             }
  479.             break;
  480.  
  481.           case Ctrl('S'):    /* ignore CTRL-S and CTRL-Q to avoid problems */
  482.           case Ctrl('Q'):    /* with terminals that use xon/xoff */
  483.               break;
  484.  
  485.           default:
  486.             clearopbeep();
  487.         }
  488.         updateScreen(VALID);
  489.         break;
  490.  
  491. /*
  492.  *      2: Control commands
  493.  */
  494.       case ':':
  495.         if (VIsual_active)
  496.             goto dooperator;
  497.         if (checkclearop())
  498.             break;
  499.         /*
  500.          * translate "count:" into ":.,.+(count - 1)"
  501.          */
  502.         if (Prenum)
  503.         {
  504.             stuffReadbuff((char_u *)".");
  505.             if (Prenum > 1)
  506.             {
  507.                 stuffReadbuff((char_u *)",.+");
  508.                 stuffnumReadbuff((long)Prenum - 1L);
  509.             }
  510.         }
  511.         do_cmdline(NULL, FALSE, FALSE);
  512.         break;
  513.  
  514.       case K_HELP:
  515.       case K_F1:
  516.         if (checkclearopq())
  517.             break;
  518.         do_help((char_u *)"");
  519.         break;
  520.  
  521.       case Ctrl('L'):
  522.         if (checkclearop())
  523.             break;
  524.         updateScreen(CLEAR);
  525.         break;
  526.  
  527.       case Ctrl('G'):
  528.         if (checkclearop())
  529.             break;
  530.             /* print full name if count given or :cd used */
  531.         fileinfo(did_cd | (int)Prenum, FALSE, FALSE);
  532.  
  533.         /*
  534.          * In Visual mode and "^O^G" in Insert mode, the message will be
  535.          * overwritten by the mode message.  Wait a bit, until a key is hit.
  536.          */
  537.         if ((VIsual_active || (restart_edit && p_smd)) && KeyTyped)
  538.         {
  539.             setcursor();
  540.             flushbuf();
  541.             mch_delay(10000L, FALSE);
  542.         }
  543.         break;
  544.  
  545.       case K_CCIRCM:            /* CTRL-^, short for ":e #" */
  546.         if (checkclearopq())
  547.             break;
  548.         (void)buflist_getfile((int)Prenum, (linenr_t)0, GETF_SETMARK|GETF_ALT);
  549.         break;
  550.  
  551.       case 'Z':         /* write, if changed, and exit */
  552.         if (checkclearopq())
  553.             break;
  554.         if (nchar != 'Z')
  555.         {
  556.             clearopbeep();
  557.             break;
  558.         }
  559.         stuffReadbuff((char_u *)":x\n");
  560.         break;
  561.  
  562.       case Ctrl(']'):            /* :ta to current identifier */
  563.       case 'K':                    /* run program for current identifier */
  564.         if (VIsual_active)        /* :ta to visual highlighted text */
  565.         {
  566.             if (VIsual.lnum != curwin->w_cursor.lnum)
  567.             {
  568.                 clearopbeep();
  569.                 break;
  570.             }
  571.             if (lt(curwin->w_cursor, VIsual))
  572.             {
  573.                 ptr = ml_get_pos(&curwin->w_cursor);
  574.                 n = VIsual.col - curwin->w_cursor.col + 1;
  575.             }
  576.             else
  577.             {
  578.                 ptr = ml_get_pos(&VIsual);
  579.                 n = curwin->w_cursor.col - VIsual.col + 1;
  580.             }
  581.             end_visual_mode();
  582.             ++RedrawingDisabled;
  583.             update_curbuf(NOT_VALID);        /* update the inversion later */
  584.             --RedrawingDisabled;
  585.         }
  586.         if (checkclearopq())
  587.             break;
  588.         /*FALLTHROUGH*/
  589.  
  590.       case 163:                    /* the pound sign, '#' for English keyboards */
  591.         if (c == 163)
  592.               c = '#';
  593.         /*FALLTHROUGH*/
  594.  
  595.       case '*':                 /* / to current identifier or string */
  596.       case '#':                 /* ? to current identifier or string */
  597. search_word:
  598.         if (c == 'g')
  599.             type = nchar;        /* "g*" or "g#" */
  600.         else
  601.             type = c;
  602.         if (ptr == NULL && (n = find_ident_under_cursor(&ptr, (type == '*' ||
  603.                     type == '#') ? FIND_IDENT|FIND_STRING : FIND_IDENT)) == 0)
  604.         {
  605.             clearop();
  606.             break;
  607.         }
  608.  
  609.         if (Prenum)
  610.             stuffnumReadbuff(Prenum);
  611.         switch (type)
  612.         {
  613.             case '*':
  614.                 stuffReadbuff((char_u *)"/");
  615.                 /* FALLTHROUGH */
  616.  
  617.             case '#':
  618.                 if (type == '#')
  619.                     stuffReadbuff((char_u *)"?");
  620.  
  621.                 /*
  622.                  * put cursor at start of word, makes search skip the word
  623.                  * under the cursor
  624.                  */
  625.                 curwin->w_cursor.col = ptr - ml_get_curline();
  626.  
  627.                 if (c != 'g' && iswordchar(*ptr))
  628.                     stuffReadbuff((char_u *)"\\<");
  629.                 no_smartcase = TRUE;        /* don't use 'smartcase' now */
  630.                 break;
  631.  
  632.             case 'K':
  633.                 if (*p_kp == NUL)
  634.                     stuffReadbuff((char_u *)":he ");
  635.                 else
  636.                 {
  637.                     stuffReadbuff((char_u *)":! ");
  638.                     stuffReadbuff(p_kp);
  639.                     stuffReadbuff((char_u *)" ");
  640.                 }
  641.                 break;
  642.             default:
  643.                 if (curbuf->b_help)
  644.                     stuffReadbuff((char_u *)":he ");
  645.                 else
  646.                     stuffReadbuff((char_u *)":ta ");
  647.         }
  648.  
  649.         /*
  650.          * Now grab the chars in the identifier
  651.          */
  652.         while (n--)
  653.         {
  654.                 /* put a backslash before \ and some others */
  655.             if (*ptr == '\\' || (!(type == '*' || type == '#') &&
  656.                                       vim_strchr(escape_chars, *ptr) != NULL))
  657.                 stuffcharReadbuff('\\');
  658.                 /* don't interpret the characters as edit commands */
  659.             if (*ptr < ' ' || *ptr > '~')
  660.                 stuffcharReadbuff(Ctrl('V'));
  661.             stuffcharReadbuff(*ptr++);
  662.         }
  663.  
  664.         if (c != 'g' && (type == '*' || type == '#') && iswordchar(ptr[-1]))
  665.             stuffReadbuff((char_u *)"\\>");
  666.         stuffReadbuff((char_u *)"\n");
  667.         break;
  668.  
  669.       case Ctrl('T'):        /* backwards in tag stack */
  670.         if (checkclearopq())
  671.             break;
  672.         do_tag((char_u *)"", 2, (int)Prenum1);
  673.         break;
  674.  
  675. /*
  676.  * Cursor motions
  677.  */
  678.       case 'G':
  679. goto_line:
  680.         op_motion_type = MLINE;
  681.         setpcmark();
  682.         if (Prenum == 0 || Prenum > curbuf->b_ml.ml_line_count)
  683.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  684.         else
  685.             curwin->w_cursor.lnum = Prenum;
  686.         beginline(MAYBE);
  687.         break;
  688.  
  689.       case 'H':
  690.       case 'M':
  691.         if (c == 'M')
  692.         {
  693.             int        used = 0;
  694.  
  695.             for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; ++n)
  696.                 if ((used += plines(curwin->w_topline + n)) >=
  697.                             (curwin->w_height - curwin->w_empty_rows + 1) / 2)
  698.                     break;
  699.             if (n && used > curwin->w_height)
  700.                 --n;
  701.         }
  702.         else
  703.             n = Prenum;
  704.         op_motion_type = MLINE;
  705.         setpcmark();
  706.         curwin->w_cursor.lnum = curwin->w_topline + n;
  707.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  708.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  709.         cursor_correct();        /* correct for 'so' */
  710.         beginline(MAYBE);
  711.         break;
  712.  
  713.       case 'L':
  714.         op_motion_type = MLINE;
  715.         setpcmark();
  716.         curwin->w_cursor.lnum = curwin->w_botline - 1;
  717.         if (Prenum >= curwin->w_cursor.lnum)
  718.             curwin->w_cursor.lnum = 1;
  719.         else
  720.             curwin->w_cursor.lnum -= Prenum;
  721.         cursor_correct();        /* correct for 'so' */
  722.         beginline(MAYBE);
  723.         break;
  724.  
  725.       case 'l':
  726.       case K_RIGHT:
  727.       case ' ':
  728.         op_motion_type = MCHAR;
  729.         op_inclusive = FALSE;
  730.         n = Prenum1;
  731.         while (n--)
  732.         {
  733.             if (oneright() == FAIL)
  734.             {
  735.                     /* space wraps to next line if 'whichwrap' bit 1 set */
  736.                     /* 'l' wraps to next line if 'whichwrap' bit 2 set */
  737.                     /* CURS_RIGHT wraps to next line if 'whichwrap' bit 3 set */
  738.                 if (((c == ' '     && vim_strchr(p_ww, 's') != NULL) ||
  739.                      (c == 'l'     && vim_strchr(p_ww, 'l') != NULL) ||
  740.                      (c == K_RIGHT && vim_strchr(p_ww, '>') != NULL)) &&
  741.                          curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  742.                 {
  743.                     /* When deleting we also count the NL as a character.
  744.                      * Set op_inclusive when last char in the line is
  745.                      * included, move to next line after that */
  746.                     if ((op_type == DELETE || op_type == CHANGE) &&
  747.                            !op_inclusive && !lineempty(curwin->w_cursor.lnum))
  748.                         op_inclusive = TRUE;
  749.                     else
  750.                     {
  751.                         ++curwin->w_cursor.lnum;
  752.                         curwin->w_cursor.col = 0;
  753.                         curwin->w_set_curswant = TRUE;
  754.                         op_inclusive = FALSE;
  755.                     }
  756.                     continue;
  757.                 }
  758.                 if (op_type == NOP)
  759.                     beep_flush();
  760.                 else
  761.                 {
  762.                     if (lineempty(curwin->w_cursor.lnum))
  763.                         clearopbeep();
  764.                     else
  765.                     {
  766.                         op_inclusive = TRUE;
  767.                         if (n)
  768.                             beep_flush();
  769.                     }
  770.                 }
  771.                 break;
  772.             }
  773.         }
  774.         break;
  775.  
  776.       case 'h':
  777.       case K_LEFT:
  778.       case K_BS:
  779.       case Ctrl('H'):
  780.         op_motion_type = MCHAR;
  781.         op_inclusive = FALSE;
  782.         n = Prenum1;
  783.         while (n--)
  784.         {
  785.             if (oneleft() == FAIL)
  786.             {
  787.                     /* backspace and del wrap to previous line if 'whichwrap'
  788.                      *       bit 0 set.
  789.                      * 'h' wraps to previous line if 'whichwrap' bit 2 set.
  790.                      * CURS_LEFT wraps to previous line if 'whichwrap' bit 3
  791.                      * set. */
  792.                 if (   (((c == K_BS || c == Ctrl('H'))
  793.                                      && vim_strchr(p_ww, 'b') != NULL) ||
  794.                         (c == 'h'    && vim_strchr(p_ww, 'h') != NULL) ||
  795.                         (c == K_LEFT && vim_strchr(p_ww, '<') != NULL)) &&
  796.                             curwin->w_cursor.lnum > 1)
  797.                 {
  798.                     --(curwin->w_cursor.lnum);
  799.                     coladvance(MAXCOL);
  800.                     curwin->w_set_curswant = TRUE;
  801.  
  802.                     /* When the NL before the first char has to be deleted we
  803.                      * put the cursor on the NUL after the previous line.
  804.                      * This is a very special case, be careful!
  805.                      * don't adjust op_end now, otherwise it won't work */
  806.                     if ((op_type == DELETE || op_type == CHANGE) &&
  807.                                             !lineempty(curwin->w_cursor.lnum))
  808.                     {
  809.                         ++curwin->w_cursor.col;
  810.                         dont_adjust_op_end = TRUE;
  811.                     }
  812.                     continue;
  813.                 }
  814.                 else if (op_type != DELETE && op_type != CHANGE)
  815.                     beep_flush();
  816.                 else if (Prenum1 == 1)
  817.                     clearopbeep();
  818.                 break;
  819.             }
  820.         }
  821.         break;
  822.  
  823.       case '-':
  824.         flag = TRUE;
  825.         /* FALLTHROUGH */
  826.  
  827.       case 'k':
  828.       case K_UP:
  829.       case Ctrl('P'):
  830. normal_k:
  831.         op_motion_type = MLINE;
  832.         if (cursor_up(Prenum1) == FAIL)
  833.             clearopbeep();
  834.         else if (flag)
  835.             beginline(TRUE);
  836.         break;
  837.  
  838.       case '+':
  839.       case CR:
  840.         flag = TRUE;
  841.         /* FALLTHROUGH */
  842.  
  843.       case 'j':
  844.       case K_DOWN:
  845.       case Ctrl('N'):
  846.       case NL:
  847. normal_j:
  848.         op_motion_type = MLINE;
  849.         if (cursor_down(Prenum1) == FAIL)
  850.             clearopbeep();
  851.         else if (flag)
  852.             beginline(TRUE);
  853.         break;
  854.  
  855.         /*
  856.          * This is a strange motion command that helps make operators more
  857.          * logical. It is actually implemented, but not documented in the
  858.          * real 'vi'. This motion command actually refers to "the current
  859.          * line". Commands like "dd" and "yy" are really an alternate form of
  860.          * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  861.          * lines.
  862.          */
  863.       case '_':
  864. lineop:
  865.         old_col = curwin->w_curswant;
  866.         op_motion_type = MLINE;
  867.         if (cursor_down((long)(Prenum1 - 1)) == FAIL)
  868.             clearopbeep();
  869.         if (op_type == DELETE || op_type == LSHIFT || op_type == RSHIFT)
  870.             beginline(MAYBE);
  871.         else if (op_type != YANK)            /* 'Y' does not move cursor */
  872.             beginline(TRUE);
  873.         break;
  874.  
  875.       case K_HOME:
  876.         if ((mod_mask & MOD_MASK_CTRL))
  877.             goto goto_line_one;
  878.         Prenum = 1;
  879.         /* FALLTHROUGH */
  880.  
  881.       case '|':
  882.         op_motion_type = MCHAR;
  883.         op_inclusive = FALSE;
  884.         beginline(FALSE);
  885.         if (Prenum > 0)
  886.         {
  887.             coladvance((colnr_t)(Prenum - 1));
  888.             curwin->w_curswant = (colnr_t)(Prenum - 1);
  889.         }
  890.         else
  891.             curwin->w_curswant = 0;
  892.         /* keep curswant at the column where we wanted to go, not where
  893.                 we ended; differs is line is too short */
  894.         curwin->w_set_curswant = FALSE;
  895.         break;
  896.  
  897.         /*
  898.          * Word Motions
  899.          */
  900.  
  901.       case 'B':
  902.         type = 1;
  903.         /* FALLTHROUGH */
  904.  
  905.       case 'b':
  906.       case K_S_LEFT:
  907.         op_motion_type = MCHAR;
  908.         op_inclusive = FALSE;
  909.         curwin->w_set_curswant = TRUE;
  910.         if (bck_word(Prenum1, type, FALSE) == FAIL)
  911.             clearopbeep();
  912.         break;
  913.  
  914.       case 'E':
  915.         type = 1;
  916.         /* FALLTHROUGH */
  917.  
  918.       case 'e':
  919.         op_inclusive = TRUE;
  920.         goto dowrdcmd;
  921.  
  922.       case 'W':
  923.         type = 1;
  924.         /* FALLTHROUGH */
  925.  
  926.       case 'w':
  927.       case K_S_RIGHT:
  928.         op_inclusive = FALSE;
  929.         flag = TRUE;
  930.         /*
  931.          * This is a little strange. To match what the real vi does, we
  932.          * effectively map 'cw' to 'ce', and 'cW' to 'cE', provided that we
  933.          * are not on a space or a TAB. This seems impolite at first, but it's
  934.          * really more what we mean when we say 'cw'.
  935.          * Another strangeness: When standing on the end of a word "ce" will
  936.          * change until the end of the next wordt, but "cw" will change only
  937.          * one character! This is done by setting type to 2.
  938.          */
  939.         if (op_type == CHANGE && (n = gchar_cursor()) != ' ' && n != TAB &&
  940.                                                                 n != NUL)
  941.         {
  942.             op_inclusive = TRUE;
  943.             flag = FALSE;
  944.             flag2 = TRUE;
  945.         }
  946.  
  947. dowrdcmd:
  948.         op_motion_type = MCHAR;
  949.         curwin->w_set_curswant = TRUE;
  950.         if (flag)
  951.             n = fwd_word(Prenum1, type, op_type != NOP);
  952.         else
  953.             n = end_word(Prenum1, type, flag2, FALSE);
  954.         if (n == FAIL)
  955.             clearopbeep();
  956.         break;
  957.  
  958.       case K_END:
  959.         if ((mod_mask & MOD_MASK_CTRL))
  960.             goto goto_line;
  961.         /* FALLTHROUGH */
  962.  
  963.       case '$':
  964.         op_motion_type = MCHAR;
  965.         op_inclusive = TRUE;
  966.         curwin->w_curswant = MAXCOL;                /* so we stay at the end */
  967.         if (cursor_down((long)(Prenum1 - 1)) == FAIL)
  968.         {
  969.             clearopbeep();
  970.             break;
  971.         }
  972.         break;
  973.  
  974.       case '^':
  975.         flag = TRUE;
  976.         /* FALLTHROUGH */
  977.  
  978.       case '0':
  979.         op_motion_type = MCHAR;
  980.         op_inclusive = FALSE;
  981.         beginline(flag);
  982.         break;
  983.  
  984. /*
  985.  * 4: Searches
  986.  */
  987.       case '?':
  988.       case '/':
  989.         if ((searchbuff = getcmdline(c, Prenum1)) == NULL)
  990.         {
  991.             clearop();
  992.             break;
  993.         }
  994.         op_motion_type = MCHAR;
  995.         op_inclusive = FALSE;
  996.         curwin->w_set_curswant = TRUE;
  997.  
  998.         n = do_search(c, searchbuff, Prenum1,
  999.                          SEARCH_MARK | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG);
  1000.         if (n == 0)
  1001.             clearop();
  1002.         else if (n == 2)
  1003.             op_motion_type = MLINE;
  1004.         break;
  1005.  
  1006.       case 'N':
  1007.         flag = SEARCH_REV;
  1008.  
  1009.       case 'n':
  1010.         op_motion_type = MCHAR;
  1011.         op_inclusive = FALSE;
  1012.         curwin->w_set_curswant = TRUE;
  1013.         if (!do_search(0, NULL, Prenum1,
  1014.                   SEARCH_MARK | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG | flag))
  1015.             clearop();
  1016.         break;
  1017.  
  1018.         /*
  1019.          * Character searches
  1020.          */
  1021.       case 'T':
  1022.         dir = BACKWARD;
  1023.         /* FALLTHROUGH */
  1024.  
  1025.       case 't':
  1026.         type = 1;
  1027.         goto docsearch;
  1028.  
  1029.       case 'F':
  1030.         dir = BACKWARD;
  1031.         /* FALLTHROUGH */
  1032.  
  1033.       case 'f':
  1034. docsearch:
  1035.         op_motion_type = MCHAR;
  1036.         if (dir == BACKWARD)
  1037.             op_inclusive = FALSE;
  1038.         else
  1039.             op_inclusive = TRUE;
  1040.         curwin->w_set_curswant = TRUE;
  1041.         if (nchar >= 0x100 || !searchc(nchar, dir, type, Prenum1))
  1042.             clearopbeep();
  1043.         break;
  1044.  
  1045.       case ',':
  1046.         flag = 1;
  1047.         /* FALLTHROUGH */
  1048.  
  1049.       case ';':
  1050.         dir = flag;
  1051.         goto docsearch;        /* nchar == NUL, thus repeat previous search */
  1052.  
  1053.         /*
  1054.          * section or C function searches
  1055.          */
  1056.       case '[':
  1057.         dir = BACKWARD;
  1058.         /* FALLTHROUGH */
  1059.  
  1060.       case ']':
  1061.         op_motion_type = MCHAR;
  1062.         op_inclusive = FALSE;
  1063.  
  1064.         /*
  1065.          * "[f" or "]f" : Edit file under the cursor (same as "gf")
  1066.          */
  1067.         if (nchar == 'f')
  1068.             goto gotofile;
  1069.  
  1070.         /*
  1071.          * Find the occurence(s) of the identifier or define under cursor
  1072.          * in current and included files or jump to the first occurence.
  1073.          *
  1074.          *                     search          list            jump 
  1075.          *                   fwd   bwd    fwd   bwd     fwd    bwd
  1076.          * identifier     "]i"  "[i"   "]I"  "[I"   "]^I"  "[^I"
  1077.          * define          "]d"  "[d"   "]D"  "[D"   "]^D"  "[^D"
  1078.          */
  1079.         if (nchar == 'i' || nchar == 'I' || nchar == Ctrl('I') ||
  1080.             nchar == 'd' || nchar == 'D' || nchar == Ctrl('D'))
  1081.         {
  1082.             int            len;
  1083.  
  1084.             if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
  1085.             {
  1086.                 clearop();
  1087.                 break;
  1088.             }
  1089.             find_pattern_in_path(ptr, len, TRUE,
  1090.                 Prenum == 0 ? !isupper(nchar) : FALSE,
  1091.                 ((nchar & 0xf) == ('d' & 0xf)) ?  FIND_DEFINE : FIND_ANY,
  1092.                 Prenum1,
  1093.                 isupper(nchar) ? ACTION_SHOW_ALL :
  1094.                             islower(nchar) ? ACTION_SHOW : ACTION_GOTO,
  1095.                 c == ']' ? curwin->w_cursor.lnum : (linenr_t)1,
  1096.                 (linenr_t)MAXLNUM);
  1097.             curwin->w_set_curswant = TRUE;
  1098.             break;
  1099.         }
  1100.  
  1101.         /*
  1102.          * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
  1103.          * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
  1104.          * "[/", "[*", "]/", "]*": go to Nth comment start/end.
  1105.          */
  1106.         if ((c == '[' && vim_strchr((char_u *)"{(*/#", nchar) != NULL) ||
  1107.             (c == ']' && vim_strchr((char_u *)"})*/#", nchar) != NULL))
  1108.         {
  1109.             FPOS old_pos;
  1110.             FPOS new_pos;
  1111.  
  1112.             if (nchar == '*')
  1113.                 nchar = '/';
  1114.             old_pos = curwin->w_cursor;
  1115.             new_pos.lnum = 0;
  1116.             while (Prenum1--)
  1117.             {
  1118.                 if ((pos = findmatchlimit(nchar,
  1119.                            (c == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL)
  1120.                 {
  1121.                     if (new_pos.lnum == 0)    /* nothing found */
  1122.                         clearopbeep();
  1123.                     else
  1124.                         pos = &new_pos;        /* use last one found */
  1125.                     break;
  1126.                 }
  1127.                 curwin->w_cursor = *pos;
  1128.                 new_pos= *pos;
  1129.             }
  1130.             curwin->w_cursor = old_pos;
  1131.             if (pos != NULL)
  1132.             {
  1133.                 setpcmark();
  1134.                 curwin->w_cursor = *pos;
  1135.                 curwin->w_set_curswant = TRUE;
  1136.             }
  1137.             break;
  1138.         }
  1139.  
  1140.         /*
  1141.          * "[[", "[]", "]]" and "][": move to start or end of function
  1142.          */
  1143.         if (nchar == '[' || nchar == ']')
  1144.         {
  1145.             if (nchar == c)                /* "]]" or "[[" */
  1146.                 flag = '{';
  1147.             else
  1148.                 flag = '}';                /* "][" or "[]" */
  1149.  
  1150.             curwin->w_set_curswant = TRUE;
  1151.             /*
  1152.              * Imitate strange vi behaviour: When using "]]" with an operator
  1153.              * we also stop at '}'.
  1154.              */
  1155.             if (!findpar(dir, Prenum1, flag,
  1156.                            (op_type != NOP && dir == FORWARD && flag == '{')))
  1157.                 clearopbeep();
  1158.             else if (op_type == NOP)
  1159.                 beginline(TRUE);
  1160.             break;
  1161.         }
  1162.  
  1163.         /*
  1164.          * "[p", "[P", "]P" and "]p": put with indent adjustment
  1165.          */
  1166.         if (nchar == 'p' || nchar == 'P')
  1167.         {
  1168.             if (checkclearopq())
  1169.                 break;
  1170.             prep_redo(Prenum, NUL, c, nchar, NUL);
  1171.             do_put((c == ']' && nchar == 'p') ? FORWARD : BACKWARD,
  1172.                                                             Prenum1, TRUE);
  1173.             break;
  1174.         }
  1175.  
  1176. #ifdef USE_MOUSE
  1177.         /*
  1178.          * [ or ] followed by a middle mouse click: put selected text with
  1179.          * indent adjustment.  Any other button just does as usual.
  1180.          */
  1181.         if (nchar >= K_LEFTMOUSE && nchar <= K_RIGHTRELEASE)
  1182.         {
  1183.             (void)do_mouse(nchar, (c == ']') ? FORWARD : BACKWARD,
  1184.                                                                Prenum1, TRUE);
  1185.             break;
  1186.         }
  1187. #endif /* USE_MOUSE */
  1188.  
  1189.         /*
  1190.          * end of '[' and ']': not a valid nchar
  1191.          */
  1192.         clearopbeep();
  1193.         break;
  1194.  
  1195.       case '%':
  1196.         op_inclusive = TRUE;
  1197.         if (Prenum)        /* {cnt}% : goto {cnt} percentage in file */
  1198.         {
  1199.             if (Prenum > 100)
  1200.                 clearopbeep();
  1201.             else
  1202.             {
  1203.                 op_motion_type = MLINE;
  1204.                 setpcmark();
  1205.                         /* round up, so CTRL-G will give same value */
  1206.                 curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count *
  1207.                                                            Prenum + 99) / 100;
  1208.                 beginline(MAYBE);
  1209.             }
  1210.         }
  1211.         else            /* % : go to matching paren */
  1212.         {
  1213.             op_motion_type = MCHAR;
  1214.             if ((pos = findmatch(NUL)) == NULL)
  1215.                 clearopbeep();
  1216.             else
  1217.             {
  1218.                 setpcmark();
  1219.                 curwin->w_cursor = *pos;
  1220.                 curwin->w_set_curswant = TRUE;
  1221.             }
  1222.         }
  1223.         break;
  1224.  
  1225.       case '(':
  1226.         dir = BACKWARD;
  1227.         /* FALLTHROUGH */
  1228.  
  1229.       case ')':
  1230.         op_motion_type = MCHAR;
  1231.         if (c == ')')
  1232.             op_inclusive = FALSE;
  1233.         else
  1234.             op_inclusive = TRUE;
  1235.         curwin->w_set_curswant = TRUE;
  1236.  
  1237.         if (findsent(dir, Prenum1) == FAIL)
  1238.             clearopbeep();
  1239.         break;
  1240.  
  1241.       case '{':
  1242.         dir = BACKWARD;
  1243.         /* FALLTHROUGH */
  1244.  
  1245.       case '}':
  1246.         op_motion_type = MCHAR;
  1247.         op_inclusive = FALSE;
  1248.         curwin->w_set_curswant = TRUE;
  1249.         if (!findpar(dir, Prenum1, NUL, FALSE))
  1250.             clearopbeep();
  1251.         break;
  1252.  
  1253. /*
  1254.  * 5: Edits
  1255.  */
  1256.       case '.':                /* redo command */
  1257.         if (checkclearopq())
  1258.             break;
  1259.         /*
  1260.          * if restart_edit is TRUE, the last but one command is repeated
  1261.          * instead of the last command (inserting text). This is used for
  1262.          * CTRL-O <.> in insert mode
  1263.          */
  1264.         if (start_redo(Prenum, restart_edit && !arrow_used) == FAIL)
  1265.             clearopbeep();
  1266.         break;
  1267.  
  1268.       case 'u':                /* undo */
  1269.         if (VIsual_active || op_type == vim_strchr(opchars, 'u') - opchars + 1)
  1270.             goto dooperator;
  1271.       case K_UNDO:
  1272.         if (checkclearopq())
  1273.             break;
  1274.         u_undo((int)Prenum1);
  1275.         curwin->w_set_curswant = TRUE;
  1276.         break;
  1277.  
  1278.       case Ctrl('R'):        /* undo undo */
  1279.         if (checkclearopq())
  1280.             break;
  1281.           u_redo((int)Prenum1);
  1282.         curwin->w_set_curswant = TRUE;
  1283.         break;
  1284.  
  1285.       case 'U':                /* Undo line */
  1286.         if (VIsual_active || op_type == vim_strchr(opchars, 'U') - opchars + 1)
  1287.             goto dooperator;
  1288.         if (checkclearopq())
  1289.             break;
  1290.         u_undoline();
  1291.         curwin->w_set_curswant = TRUE;
  1292.         break;
  1293.  
  1294.       case 'r':
  1295.         if (VIsual_active)
  1296.         {
  1297.             c = 'c';
  1298.             goto dooperator;
  1299.         }
  1300.         if (checkclearop())
  1301.             break;
  1302.         ptr = ml_get_cursor();
  1303.             /* special key or not enough characters to replace */
  1304.         if (nchar >= 0x100 || STRLEN(ptr) < (unsigned)Prenum1)
  1305.         {
  1306.             clearopbeep();
  1307.             break;
  1308.         }
  1309.         /*
  1310.          * Replacing with a TAB is done by edit(), because it is complicated
  1311.          * when 'expandtab' is set.
  1312.          * Other characters are done below to avoid problems with things like
  1313.          * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
  1314.          */
  1315.         if (nchar == '\t' && curbuf->b_p_et)
  1316.         {
  1317.             prep_redo(Prenum1, NUL, 'r', '\t', NUL);
  1318.             stuffnumReadbuff(Prenum1);
  1319.             stuffcharReadbuff('R');
  1320.             stuffcharReadbuff('\t');
  1321.             stuffcharReadbuff(ESC);
  1322.             break;
  1323.         }
  1324.  
  1325.         if (nchar == Ctrl('V'))                /* get another character */
  1326.         {
  1327.             c = Ctrl('V');
  1328.             nchar = get_literal();
  1329.         }
  1330.         else
  1331.             c = NUL;
  1332.         prep_redo(Prenum1, NUL, 'r', c, nchar);
  1333.         if (u_save_cursor() == FAIL)        /* save line for undo */
  1334.             break;
  1335.         /*
  1336.          * Replace characters by a newline.
  1337.          * Strange vi behaviour: Only one newline is inserted.
  1338.          * Delete the characters here.
  1339.          * Insert the newline with an insert command, takes care of
  1340.          * autoindent.
  1341.          */
  1342.         if (c != Ctrl('V') && (nchar == '\r' || nchar == '\n'))
  1343.         {
  1344.             while (Prenum1--)                    /* delete the characters */
  1345.                 delchar(FALSE);
  1346.                 /* replacing the last character of a line is different */
  1347.             if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
  1348.             {
  1349.                 --curwin->w_cursor.col;
  1350.                 stuffcharReadbuff('a');
  1351.             }
  1352.             else
  1353.                 stuffcharReadbuff('i');
  1354.             stuffcharReadbuff('\r');
  1355.             stuffcharReadbuff(ESC);
  1356.         }
  1357.         else
  1358.         {
  1359.             while (Prenum1--)                    /* replace the characters */
  1360.             {
  1361.                 /*
  1362.                  * Replace a 'normal' character.
  1363.                  * Get ptr again, because u_save and/or showmatch() will have
  1364.                  * released the line.  At the same time we let know that the
  1365.                  * line will be changed.
  1366.                  */
  1367.                 ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
  1368.                 ptr[curwin->w_cursor.col] = nchar;
  1369.                 if (p_sm && (nchar == ')' || nchar == '}' || nchar == ']'))
  1370.                     showmatch();
  1371.                 ++curwin->w_cursor.col;
  1372.             }
  1373.             --curwin->w_cursor.col;        /* cursor on the last replaced char */
  1374.         }
  1375.         curwin->w_set_curswant = TRUE;
  1376.         CHANGED;
  1377.         updateline();
  1378.         set_last_insert(nchar);
  1379.         break;
  1380.  
  1381.       case 'J':
  1382.         if (VIsual_active)        /* join the visual lines */
  1383.             goto dooperator;
  1384.         if (checkclearop())
  1385.             break;
  1386.         if (Prenum <= 1)
  1387.             Prenum = 2;             /* default for join is two lines! */
  1388.         if (curwin->w_cursor.lnum + Prenum - 1 > curbuf->b_ml.ml_line_count)
  1389.         {
  1390.             clearopbeep();            /* beyond last line */
  1391.             break;
  1392.         }
  1393.  
  1394.         prep_redo(Prenum, NUL, 'J', NUL, NUL);
  1395.         do_do_join(Prenum, TRUE, TRUE);
  1396.         break;
  1397.  
  1398.       case 'P':
  1399.         dir = BACKWARD;
  1400.         /* FALLTHROUGH */
  1401.  
  1402.       case 'p':
  1403.         /*
  1404.          * 'P' after an operator or with Visual: Set current block.
  1405.          * 'p' after an operator or with Visual: Set current paragraph.
  1406.          */
  1407.         if (op_type != NOP || VIsual_active)
  1408.         {
  1409.             if (c == 'P')
  1410.             {
  1411.                 if (current_block('{', Prenum1) == FAIL)
  1412.                     clearopbeep();
  1413.             }
  1414.             else
  1415.             {
  1416.                 if (current_par(c, Prenum1) == FAIL)
  1417.                     clearopbeep();
  1418.             }
  1419.             curwin->w_set_curswant = TRUE;
  1420.         }
  1421.         else
  1422.         {
  1423.             prep_redo(Prenum, NUL, c, NUL, NUL);
  1424.             do_put(dir, Prenum1, FALSE);
  1425.         }
  1426.         break;
  1427.  
  1428.       case Ctrl('A'):            /* add to number */
  1429.       case Ctrl('X'):            /* subtract from number */
  1430.         if (checkclearopq())
  1431.             break;
  1432.         if (do_addsub((int)c, Prenum1) == OK)
  1433.             prep_redo(Prenum1, NUL, c, NUL, NUL);
  1434.         break;
  1435.  
  1436. /*
  1437.  * 6: Inserts
  1438.  */
  1439.       case 'A':
  1440.           type = 1;
  1441.         /* FALLTHROUGH */
  1442.  
  1443.       case 'a':
  1444.         if (op_type != NOP || VIsual_active)
  1445.         {
  1446.             if (current_word(Prenum1, type) == FAIL)
  1447.                 clearopbeep();
  1448.             curwin->w_set_curswant = TRUE;
  1449.         }
  1450.         else
  1451.         {
  1452.             if (c == 'A')
  1453.             {
  1454.                 curwin->w_set_curswant = TRUE;
  1455.                 while (oneright() == OK)
  1456.                     ;
  1457.             }
  1458.  
  1459.             /* Works just like an 'i'nsert on the next character. */
  1460.             if (u_save_cursor() == OK)
  1461.             {
  1462.                 if (!lineempty(curwin->w_cursor.lnum))
  1463.                     inc_cursor();
  1464.                 command_busy = edit(c, FALSE, Prenum1);
  1465.             }
  1466.         }
  1467.         break;
  1468.  
  1469.       case 'I':
  1470.         if (checkclearopq())
  1471.             break;
  1472.         beginline(TRUE);
  1473.         /* FALLTHROUGH */
  1474.  
  1475.       case 'i':
  1476.       case K_INS:
  1477. insert_command:
  1478.         if (checkclearopq())
  1479.             break;
  1480.         if (u_save_cursor() == OK)
  1481.             command_busy = edit(c, FALSE, Prenum1);
  1482.         break;
  1483.  
  1484.       case 'o':
  1485.           if (VIsual_active)    /* switch start and end of visual */
  1486.         {
  1487.             Prenum = VIsual.lnum;
  1488.             VIsual.lnum = curwin->w_cursor.lnum;
  1489.             curwin->w_cursor.lnum = Prenum;
  1490.             n = VIsual.col;
  1491.             VIsual.col = curwin->w_cursor.col;
  1492.             curwin->w_cursor.col = (int)n;
  1493.             curwin->w_set_curswant = TRUE;
  1494.             break;
  1495.         }
  1496.         if (checkclearop())
  1497.             break;
  1498.         if (has_format_option(FO_OPEN_COMS))
  1499.             fo_do_comments = TRUE;
  1500.         if (u_save(curwin->w_cursor.lnum,
  1501.                                 (linenr_t)(curwin->w_cursor.lnum + 1)) == OK &&
  1502.                         Opencmd(FORWARD, TRUE, FALSE))
  1503.             command_busy = edit('o', TRUE, Prenum1);
  1504.         fo_do_comments = FALSE;
  1505.         break;
  1506.  
  1507.       case 'O':
  1508.         if (checkclearopq())
  1509.             break;
  1510.         if (has_format_option(FO_OPEN_COMS))
  1511.             fo_do_comments = TRUE;
  1512.         if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
  1513.                curwin->w_cursor.lnum) == OK && Opencmd(BACKWARD, TRUE, FALSE))
  1514.             command_busy = edit('O', TRUE, Prenum1);
  1515.         fo_do_comments = FALSE;
  1516.         break;
  1517.  
  1518.       case 'R':
  1519.         if (VIsual_active)
  1520.         {
  1521.             c = 'c';
  1522.             VIsual_mode = 'V';
  1523.             goto dooperator;
  1524.         }
  1525.         if (checkclearopq())
  1526.             break;
  1527.         if (u_save_cursor() == OK)
  1528.             command_busy = edit('R', FALSE, Prenum1);
  1529.         break;
  1530.  
  1531. /*
  1532.  * 7: Operators
  1533.  */
  1534.       case '~':         /* swap case */
  1535.       /*
  1536.        * if tilde is not an operator and Visual is off: swap case
  1537.        * of a single character
  1538.        */
  1539.         if (!p_to && !VIsual_active &&
  1540.                     op_type != vim_strchr(opchars, '~') - opchars + 1)
  1541.         {
  1542.             if (checkclearopq())
  1543.                 break;
  1544.             if (lineempty(curwin->w_cursor.lnum))
  1545.             {
  1546.                 clearopbeep();
  1547.                 break;
  1548.             }
  1549.             prep_redo(Prenum, NUL, '~', NUL, NUL);
  1550.  
  1551.             if (u_save_cursor() == FAIL)
  1552.                 break;
  1553.  
  1554.             for (; Prenum1 > 0; --Prenum1)
  1555.             {
  1556.                 if (gchar_cursor() == NUL)
  1557.                     break;
  1558.                 swapchar(&curwin->w_cursor);
  1559.                 inc_cursor();
  1560.             }
  1561.  
  1562.             curwin->w_set_curswant = TRUE;
  1563.             CHANGED;
  1564.             updateline();
  1565.             break;
  1566.         }
  1567.         /*FALLTHROUGH*/
  1568.  
  1569.       case 'd':
  1570.       case 'c':
  1571.       case 'y':
  1572.       case '>':
  1573.       case '<':
  1574.       case '!':
  1575.       case '=':
  1576.       case 'Q':                    /* should start Ex mode */
  1577. dooperator:
  1578.         n = vim_strchr(opchars, c) - opchars + 1;
  1579.         if (n == op_type)        /* double operator works on lines */
  1580.             goto lineop;
  1581.         if (checkclearop())
  1582.             break;
  1583.         if (Prenum != 0)
  1584.             opnum = Prenum;
  1585.         curbuf->b_op_start = curwin->w_cursor;
  1586.         op_type = (int)n;
  1587.         break;
  1588.  
  1589. /*
  1590.  * 8: Abbreviations
  1591.  */
  1592.  
  1593.      /* when Visual the next commands are operators */
  1594.       case K_DEL:
  1595.               c = 'x';            /* DEL key behaves like 'x' */
  1596.       case 'S':
  1597.       case 'Y':
  1598.       case 'D':
  1599.       case 'C':
  1600.       case 'x':
  1601.       case 'X':
  1602.       case 's':
  1603.         /*
  1604.          * 's' or 'S' with an operator: Operate on sentence or section.
  1605.          */
  1606.         if (op_type != NOP || VIsual_active)
  1607.         {
  1608.             if (c == 's')        /* sentence */
  1609.             {
  1610.                 if (current_sent(Prenum1) == FAIL)
  1611.                     clearopbeep();
  1612.                 curwin->w_set_curswant = TRUE;
  1613.                 break;
  1614.             }
  1615.             if (c == 'S')        /* block with () */
  1616.             {
  1617.                 if (current_block('(', Prenum1) == FAIL)
  1618.                     clearopbeep();
  1619.                 curwin->w_set_curswant = TRUE;
  1620.                 break;
  1621.             }
  1622.         }
  1623.           if (VIsual_active)
  1624.         {
  1625.             static char_u trans[] = "YyDdCcxdXd";
  1626.  
  1627.                                             /* uppercase means linewise */
  1628.             if (isupper(c) && VIsual_mode != Ctrl('V'))
  1629.                 VIsual_mode = 'V';
  1630.             c = *(vim_strchr(trans, c) + 1);
  1631.             goto dooperator;
  1632.         }
  1633.  
  1634.       case '&':
  1635.         if (checkclearopq())
  1636.             break;
  1637.         if (Prenum)
  1638.             stuffnumReadbuff(Prenum);
  1639.  
  1640.         {
  1641.                 static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh",
  1642.                                           (char_u *)"d$", (char_u *)"c$",
  1643.                                           (char_u *)"cl", (char_u *)"cc",
  1644.                                           (char_u *)"yy", (char_u *)":s\r"};
  1645.                 static char_u *str = (char_u *)"xXDCsSY&";
  1646.  
  1647.                 stuffReadbuff(ar[(int)(vim_strchr(str, c) - str)]);
  1648.         }
  1649.         break;
  1650.  
  1651. /*
  1652.  * 9: Marks
  1653.  */
  1654.  
  1655.       case 'm':
  1656.         if (checkclearop())
  1657.             break;
  1658.         if (setmark(nchar) == FAIL)
  1659.             clearopbeep();
  1660.         break;
  1661.  
  1662.       case '\'':
  1663.         flag = TRUE;
  1664.         /* FALLTHROUGH */
  1665.  
  1666.       case '`':
  1667.         pos = getmark(nchar, (op_type == NOP));
  1668.         if (pos == (FPOS *)-1)    /* jumped to other file */
  1669.         {
  1670.             if (flag)
  1671.                 beginline(TRUE);
  1672.             break;
  1673.         }
  1674.  
  1675. cursormark:
  1676.         if (check_mark(pos) == FAIL)
  1677.             clearop();
  1678.         else
  1679.         {
  1680.             if (c == '\'' || c == '`')
  1681.                 setpcmark();
  1682.             curwin->w_cursor = *pos;
  1683.             if (flag)
  1684.                 beginline(TRUE);
  1685.         }
  1686.         op_motion_type = flag ? MLINE : MCHAR;
  1687.         op_inclusive = FALSE;        /* ignored if not MCHAR */
  1688.         curwin->w_set_curswant = TRUE;
  1689.         break;
  1690.  
  1691.     case Ctrl('O'):            /* goto older pcmark */
  1692.         Prenum1 = -Prenum1;
  1693.         /* FALLTHROUGH */
  1694.  
  1695.     case Ctrl('I'):            /* goto newer pcmark */
  1696.         if (checkclearopq())
  1697.             break;
  1698.         pos = movemark((int)Prenum1);
  1699.         if (pos == (FPOS *)-1)    /* jump to other file */
  1700.         {
  1701.             curwin->w_set_curswant = TRUE;
  1702.             break;
  1703.         }
  1704.         if (pos != NULL)    /* can jump */
  1705.             goto cursormark;
  1706.         clearopbeep();
  1707.         break;
  1708.  
  1709. /*
  1710.  * 10. Buffer setting
  1711.  */
  1712.       case '"':
  1713.         if (checkclearop())
  1714.             break;
  1715.         if (nchar != NUL && is_yank_buffer(nchar, FALSE))
  1716.         {
  1717.             yankbuffer = nchar;
  1718.             opnum = Prenum;        /* remember count before '"' */
  1719.         }
  1720.         else
  1721.             clearopbeep();
  1722.         break;
  1723.  
  1724. /*
  1725.  * 11. Visual
  1726.  */
  1727.        case 'v':
  1728.       case 'V':
  1729.       case Ctrl('V'):
  1730.         if (checkclearop())
  1731.             break;
  1732.  
  1733.             /* change Visual mode */
  1734.         if (VIsual_active)
  1735.         {
  1736.             if (VIsual_mode == c)            /* stop visual mode */
  1737.             {
  1738.                 end_visual_mode();
  1739.             }
  1740.             else                            /* toggle char/block mode */
  1741.             {                                /*     or char/line mode */
  1742.                 VIsual_mode = c;
  1743.                 showmode();
  1744.             }
  1745.             update_curbuf(NOT_VALID);        /* update the inversion */
  1746.         }
  1747.             /* start Visual mode */
  1748.         else
  1749.         {
  1750.             VIsual_save = VIsual;            /* keep for "gv" */
  1751.             VIsual_mode_save = VIsual_mode;
  1752.             start_visual_highlight();
  1753.             if (Prenum)                        /* use previously selected part */
  1754.             {
  1755.                 if (resel_VIsual_mode == NUL)    /* there is none */
  1756.                 {
  1757.                     beep_flush();
  1758.                     break;
  1759.                 }
  1760.                 VIsual = curwin->w_cursor;
  1761.                 VIsual_active = TRUE;
  1762. #ifdef USE_MOUSE
  1763.                 setmouse();
  1764. #endif
  1765.                 if (p_smd)
  1766.                     redraw_cmdline = TRUE;        /* show visual mode later */
  1767.                 /*
  1768.                  * For V and ^V, we multiply the number of lines even if there
  1769.                  * was only one -- webb
  1770.                  */
  1771.                 if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
  1772.                 {
  1773.                     curwin->w_cursor.lnum += resel_VIsual_line_count * Prenum - 1;
  1774.                     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1775.                         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1776.                 }
  1777.                 VIsual_mode = resel_VIsual_mode;
  1778.                 if (VIsual_mode == 'v')
  1779.                 {
  1780.                     if (resel_VIsual_line_count <= 1)
  1781.                         curwin->w_cursor.col += resel_VIsual_col * Prenum - 1;
  1782.                     else
  1783.                         curwin->w_cursor.col = resel_VIsual_col;
  1784.                 }
  1785.                 if (resel_VIsual_col == MAXCOL)
  1786.                 {
  1787.                     curwin->w_curswant = MAXCOL;
  1788.                     coladvance(MAXCOL);
  1789.                 }
  1790.                 else if (VIsual_mode == Ctrl('V'))
  1791.                 {
  1792.                     curwin->w_curswant = curwin->w_virtcol +
  1793.                                             resel_VIsual_col * Prenum - 1;
  1794.                     coladvance((colnr_t)curwin->w_curswant);
  1795.                 }
  1796.                 else
  1797.                     curwin->w_set_curswant = TRUE;
  1798.                 curs_columns(TRUE);            /* recompute w_virtcol */
  1799.                 update_curbuf(NOT_VALID);    /* show the inversion */
  1800.             }
  1801.             else
  1802.             {
  1803.                 VIsual = curwin->w_cursor;
  1804.                 VIsual_mode = c;
  1805.                 VIsual_active = TRUE;
  1806. #ifdef USE_MOUSE
  1807.                 setmouse();
  1808. #endif
  1809.                 if (p_smd)
  1810.                     redraw_cmdline = TRUE;    /* show visual mode later */
  1811.                 updateline();                /* start the inversion */
  1812.             }
  1813.         }
  1814.         break;
  1815.  
  1816. /*
  1817.  * 12. Suspend
  1818.  */
  1819.  
  1820.      case Ctrl('Z'):
  1821.         clearop();
  1822.         if (VIsual_active)
  1823.             end_visual_mode();                /* stop Visual */
  1824.         stuffReadbuff((char_u *)":st\r");    /* with autowrite */
  1825.         break;
  1826.  
  1827. /*
  1828.  * 13. Window commands
  1829.  */
  1830.  
  1831.      case Ctrl('W'):
  1832.         if (checkclearop())
  1833.             break;
  1834.         do_window(nchar, Prenum);            /* everything is in window.c */
  1835.         break;
  1836.  
  1837. /*
  1838.  *   14. extended commands (starting with 'g')
  1839.  */
  1840.      case 'g':
  1841.         switch (nchar)
  1842.         {
  1843.             /*
  1844.              * "gv": reselect the previous visual area
  1845.              */
  1846.             case 'v':
  1847.                 if (checkclearop())
  1848.                     break;
  1849.                 if (VIsual_active)
  1850.                     pos = &VIsual_save;
  1851.                 else
  1852.                     pos = &VIsual;
  1853.                 if (pos->lnum == 0 || pos->lnum > curbuf->b_ml.ml_line_count ||
  1854.                                                          VIsual_end.lnum == 0)
  1855.                     beep_flush();
  1856.                 else
  1857.                 {
  1858.                     FPOS    tt;
  1859.                     int        t;
  1860.  
  1861.                     /* exchange previous and current visual area */
  1862.                     if (VIsual_active)
  1863.                     {
  1864.                         tt = VIsual;
  1865.                         VIsual = VIsual_save;
  1866.                         VIsual_save = tt;
  1867.                         t = VIsual_mode;
  1868.                         VIsual_mode = VIsual_mode_save;
  1869.                         VIsual_mode_save = t;
  1870.                         tt = curwin->w_cursor;
  1871.                     }
  1872.                     curwin->w_cursor = VIsual_end;
  1873.                     if (VIsual_active)
  1874.                         VIsual_end = tt;
  1875.                     check_cursor();
  1876.                     VIsual_active = TRUE;
  1877. #ifdef USE_MOUSE
  1878.                     setmouse();
  1879. #endif
  1880.                     update_curbuf(NOT_VALID);
  1881.                     showmode();
  1882.                 }
  1883.                 break;
  1884.  
  1885.             /*
  1886.              * "gj" and "gk" two new funny movement keys -- up and down
  1887.              * movement based on *screen* line rather than *file* line.
  1888.              */
  1889.             case 'j':
  1890.             case K_DOWN:
  1891.                 if (!curwin->w_p_wrap)
  1892.                     goto normal_j;
  1893.                 if (screengo(FORWARD, Prenum1) == FAIL)
  1894.                     clearopbeep();
  1895.                 break;
  1896.  
  1897.             case 'k':
  1898.             case K_UP:
  1899.                 if (!curwin->w_p_wrap)
  1900.                     goto normal_k;
  1901.                 if (screengo(BACKWARD, Prenum1) == FAIL)
  1902.                     clearopbeep();
  1903.                 break;
  1904.  
  1905.             /*
  1906.              * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines.
  1907.              */
  1908.             case '^':
  1909.                 flag = TRUE;
  1910.                 /* FALLTHROUGH */
  1911.  
  1912.             case '0':
  1913.             case K_HOME:
  1914.                 op_motion_type = MCHAR;
  1915.                 op_inclusive = FALSE;
  1916.                 if (curwin->w_p_wrap)
  1917.                 {
  1918.                     n = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
  1919.                                                                Columns) * Columns;
  1920.                     if (curwin->w_p_nu && n > 8)
  1921.                         n -= 8;
  1922.                 }
  1923.                 else
  1924.                     n = curwin->w_leftcol;
  1925.                 coladvance((colnr_t)n);
  1926.                 if (flag)
  1927.                     while (vim_iswhite(gchar_cursor()) && oneright() == OK)
  1928.                         ;
  1929.                 curwin->w_set_curswant = TRUE;
  1930.                 break;
  1931.  
  1932.             case '$':
  1933.             case K_END:
  1934.                 op_motion_type = MCHAR;
  1935.                 op_inclusive = TRUE;
  1936.                 if (curwin->w_p_wrap)
  1937.                 {
  1938.                     curwin->w_curswant = MAXCOL;        /* so we stay at the end */
  1939.                     if (Prenum1 == 1)
  1940.                     {
  1941.                         n = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
  1942.                                                        Columns + 1) * Columns - 1;
  1943.                         if (curwin->w_p_nu && n > 8)
  1944.                             n -= 8;
  1945.                         coladvance((colnr_t)n);
  1946.                     }
  1947.                     else if (screengo(FORWARD, Prenum1 - 1) == FAIL)
  1948.                         clearopbeep();
  1949.                 }
  1950.                 else
  1951.                 {
  1952.                     n = curwin->w_leftcol + Columns - 1;
  1953.                     if (curwin->w_p_nu)
  1954.                         n -= 8;
  1955.                     coladvance((colnr_t)n);
  1956.                     curwin->w_set_curswant = TRUE;
  1957.                 }
  1958.                 break;
  1959.  
  1960.             /*
  1961.              * "g*" and "g#", like "*" and "#" but without using "\<" and "\>"
  1962.              */
  1963.             case '*':
  1964.             case '#':
  1965.                 goto search_word;
  1966.  
  1967.             /*
  1968.              * ge and gE: go back to end of word
  1969.              */
  1970.             case 'e':
  1971.             case 'E':
  1972.                 op_motion_type = MCHAR;
  1973.                 curwin->w_set_curswant = TRUE;
  1974.                 op_inclusive = TRUE;
  1975.                 if (bckend_word(Prenum1, nchar == 'E', FALSE) == FAIL)
  1976.                     clearopbeep();
  1977.                 break;
  1978.  
  1979.             /*
  1980.              * g CTRL-G: display info about cursor position
  1981.              */
  1982.             case Ctrl('G'):
  1983.                 cursor_pos_info();
  1984.                 break;
  1985.  
  1986.             /*
  1987.              * "gI": Start insert in column 1.
  1988.              */
  1989.             case 'I':
  1990.                 beginline(FALSE);
  1991.                 goto insert_command;
  1992.  
  1993.             /*
  1994.              * "gf": goto file, edit file under cursor
  1995.              * "]f" and "[f": can also be used.
  1996.              */
  1997.             case 'f':
  1998. gotofile:
  1999.                 ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP);
  2000.                 if (ptr != NULL)
  2001.                 {
  2002.                     /* do autowrite if necessary */
  2003.                     if (curbuf->b_changed && curbuf->b_nwindows <= 1 && !p_hid)
  2004.                         autowrite(curbuf);
  2005.                     setpcmark();
  2006.                     (void)do_ecmd(0, ptr, NULL, NULL, p_hid, (linenr_t)0,
  2007.                                                                        FALSE);
  2008.                     vim_free(ptr);
  2009.                 }
  2010.                 else
  2011.                     clearop();
  2012.                 break;
  2013.  
  2014.             /*
  2015.              * "gs": Goto sleep, but keep on checking for CTRL-C
  2016.              */
  2017.             case 's':
  2018.                 while (Prenum1-- && !got_int)
  2019.                 {
  2020.                     mch_delay(1000L, TRUE);
  2021.                     mch_breakcheck();
  2022.                 }
  2023.                 break;
  2024.  
  2025.             /*
  2026.              * "ga": Display the ascii value of the character under the
  2027.              * cursor.  It is displayed in decimal, hex, and octal. -- webb
  2028.              */
  2029.             case 'a':
  2030.                 do_ascii();
  2031.                 break;
  2032.  
  2033.             /*
  2034.              * "gg": Goto the first line in file.  With a count it goes to
  2035.              * that line number like for G. -- webb
  2036.              */
  2037.             case 'g':
  2038. goto_line_one:
  2039.                 if (Prenum == 0)
  2040.                     Prenum = 1;
  2041.                 goto goto_line;
  2042.  
  2043.             /*
  2044.              * Operater to format text:
  2045.              *   gq        same as 'Q' operator.
  2046.              * Operators to change the case of text:
  2047.              *   g~        Toggle the case of the text.
  2048.              *   gu        Change text to lower case.
  2049.              *   gU        Change text to upper case.
  2050.              *                                    --webb
  2051.              */
  2052.             case 'q':
  2053.             case '~':
  2054.             case 'u':
  2055.             case 'U':
  2056.                 prechar = c;
  2057.                 c = nchar;
  2058.                 goto dooperator;
  2059.  
  2060.         /*
  2061.          * "gd": Find first occurence of pattern under the cursor in the
  2062.          *       current function
  2063.          * "gD": idem, but in the current file.
  2064.          */
  2065.             case 'd':
  2066.             case 'D':
  2067.                 do_gd(nchar);
  2068.                 break;
  2069.  
  2070. #ifdef USE_MOUSE
  2071.             /*
  2072.              * g<*Mouse> : <C-*mouse>
  2073.              */
  2074.             case K_MIDDLEMOUSE:
  2075.             case K_MIDDLEDRAG:
  2076.             case K_MIDDLERELEASE:
  2077.             case K_LEFTMOUSE:
  2078.             case K_LEFTDRAG:
  2079.             case K_LEFTRELEASE:
  2080.             case K_RIGHTMOUSE:
  2081.             case K_RIGHTDRAG:
  2082.             case K_RIGHTRELEASE:
  2083.                 mod_mask = MOD_MASK_CTRL;
  2084.                 (void)do_mouse(nchar, BACKWARD, Prenum1, FALSE);
  2085.                 break;
  2086.  
  2087.             case K_IGNORE:
  2088.                 break;
  2089. #endif
  2090.  
  2091.             default:
  2092.                 clearopbeep();
  2093.                 break;
  2094.         }
  2095.         break;
  2096.  
  2097. /*
  2098.  * 15. mouse click
  2099.  */
  2100. #ifdef USE_MOUSE
  2101.       case K_MIDDLEMOUSE:
  2102.       case K_MIDDLEDRAG:
  2103.       case K_MIDDLERELEASE:
  2104.       case K_LEFTMOUSE:
  2105.       case K_LEFTDRAG:
  2106.       case K_LEFTRELEASE:
  2107.       case K_RIGHTMOUSE:
  2108.       case K_RIGHTDRAG:
  2109.       case K_RIGHTRELEASE:
  2110.         (void)do_mouse(c, BACKWARD, Prenum1, FALSE);
  2111.         break;
  2112.  
  2113.       case K_IGNORE:
  2114.         break;
  2115. #endif
  2116.  
  2117. #ifdef USE_GUI
  2118. /*
  2119.  * 16. scrollbar movement
  2120.  */
  2121.       case K_SCROLLBAR:
  2122.         if (op_type != NOP)
  2123.             clearopbeep();
  2124.  
  2125.         /* Even if an operator was pending, we still want to scroll */
  2126.         gui_do_scroll();
  2127.         break;
  2128.  
  2129.       case K_HORIZ_SCROLLBAR:
  2130.         if (op_type != NOP)
  2131.             clearopbeep();
  2132.  
  2133.         /* Even if an operator was pending, we still want to scroll */
  2134.         gui_do_horiz_scroll();
  2135.         break;
  2136. #endif
  2137.  
  2138. /*
  2139.  * 17. The end
  2140.  */
  2141.       case ESC:
  2142.         /* Don't drop through and beep if we are canceling a command: */
  2143.         if (!VIsual_active && (op_type != NOP ||
  2144.                                                opnum || Prenum || yankbuffer))
  2145.         {
  2146.             clearop();                    /* don't beep */
  2147.             break;
  2148.         }
  2149.         if (VIsual_active)
  2150.         {
  2151.             end_visual_mode();            /* stop Visual */
  2152.             update_curbuf(NOT_VALID);
  2153.             clearop();                    /* don't beep */
  2154.             break;
  2155.         }
  2156.         /* ESC in normal mode: beep, but don't flush buffers */
  2157.         clearop();
  2158.         vim_beep();
  2159.         break;
  2160.  
  2161.       default:                    /* not a known command */
  2162.         clearopbeep();
  2163.         break;
  2164.  
  2165.     }    /* end of switch on command character */
  2166.  
  2167. /*
  2168.  * if we didn't start or finish an operator, reset yankbuffer, unless we
  2169.  * need it later.
  2170.  */
  2171.     if (!finish_op && !op_type && vim_strchr((char_u *)"\"DCYSsXx.", c) == NULL)
  2172.         yankbuffer = 0;
  2173.  
  2174. /*
  2175.  * If an operation is pending, handle it...
  2176.  */
  2177.     do_pending_operator(c, nchar, finish_op, searchbuff, 
  2178.                       &command_busy, old_col, FALSE, dont_adjust_op_end);
  2179.  
  2180. normal_end:
  2181.     if (op_type == NOP && yankbuffer == 0)
  2182.         clear_showcmd();
  2183.  
  2184.     if (restart_edit && op_type == NOP && !VIsual_active
  2185.                          && !command_busy && stuff_empty() && yankbuffer == 0)
  2186.         (void)edit(restart_edit, FALSE, 1L);
  2187.  
  2188.     checkpcmark();            /* check if we moved since setting pcmark */
  2189.     vim_free(searchbuff);
  2190.  
  2191. /*
  2192.  * Update the other windows for the current buffer if modified has been set in
  2193.  * set_Changed() (This should be done more efficiently)
  2194.  */
  2195.     if (modified)
  2196.     {
  2197.         WIN        *wp;
  2198.  
  2199.         for (wp = firstwin; wp; wp = wp->w_next)
  2200.             if (wp != curwin && wp->w_buffer == curbuf)
  2201.             {
  2202.                 cursor_off();
  2203.                 wp->w_redr_type = NOT_VALID;
  2204.                 /*
  2205.                  * don't do the actual redraw if wait_return() has just been
  2206.                  * called and the user typed a ":"
  2207.                  */
  2208.                 if (!skip_redraw)
  2209.                     win_update(wp);
  2210.             }
  2211.         modified = FALSE;
  2212.     }
  2213. }
  2214.  
  2215. /*
  2216.  * Handle an operator after visual mode or when the movement is finished
  2217.  */
  2218.     void
  2219. do_pending_operator(c, nchar, finish_op, searchbuff, command_busy,
  2220.                                         old_col, gui_yank, dont_adjust_op_end)
  2221.     register int    c;
  2222.     int                nchar;
  2223.     int                finish_op;
  2224.     char_u            *searchbuff;
  2225.     int                *command_busy;
  2226.     int                old_col;
  2227.     int                gui_yank;        /* yanking visual area for GUI */
  2228.     int                dont_adjust_op_end;
  2229. {
  2230.     /* The visual area is remembered for redo */
  2231.     static int        redo_VIsual_mode = NUL;    /* 'v', 'V', or Ctrl-V */
  2232.     static linenr_t    redo_VIsual_line_count;        /* number of lines */
  2233.     static colnr_t    redo_VIsual_col;        /* number of cols or end column */
  2234.     static long        redo_VIsual_Prenum;        /* Prenum for operator */
  2235.  
  2236.     linenr_t        Prenum1 = 1L;
  2237.     FPOS            old_cursor;
  2238.     int                VIsual_was_active = VIsual_active;
  2239.     int                redraw;
  2240.  
  2241. #ifdef USE_GUI
  2242.     /*
  2243.      * Yank the visual area into the GUI selection register before we operate
  2244.      * on it and lose it forever.  This could call do_pending_operator()
  2245.      * recursively, but that's OK because gui_yank will be TRUE for the
  2246.      * nested call.  Note also that we call gui_copy_selection() and not
  2247.      * gui_auto_select().  This is because even when 'autoselect' is not set,
  2248.      * if we operate on the text, eg by deleting it, then this is considered to
  2249.      * be an explicit request for it to be put in the global cut buffer, so we
  2250.      * always want to do it here. -- webb
  2251.      */
  2252.     if (gui.in_use && op_type != NOP && !gui_yank && VIsual_active
  2253.                                                          && !redo_VIsual_busy)
  2254.         gui_copy_selection();
  2255. #endif
  2256.     old_cursor = curwin->w_cursor;
  2257.  
  2258.     /*
  2259.      * If an operation is pending, handle it...
  2260.      */
  2261.     if ((VIsual_active || finish_op) && op_type != NOP)
  2262.     {
  2263.         op_is_VIsual = VIsual_active;
  2264.         if (op_type != YANK && !VIsual_active)        /* can't redo yank */
  2265.         {
  2266.             prep_redo(Prenum, prechar, opchars[op_type - 1], c, nchar);
  2267.             if (c == '/' || c == '?')                /* was a search */
  2268.             {
  2269.                 /*
  2270.                  * If 'cpoptions' does not contain 'r', insert the search
  2271.                  * pattern to really repeat the same command.
  2272.                  */
  2273.                 if (vim_strchr(p_cpo, CPO_REDO) == NULL)
  2274.                     AppendToRedobuff(searchbuff);
  2275.                 AppendToRedobuff(NL_STR);
  2276.             }
  2277.         }
  2278.  
  2279.         if (redo_VIsual_busy)
  2280.         {
  2281.             curbuf->b_op_start = curwin->w_cursor;
  2282.             curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
  2283.             if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  2284.                 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  2285.             VIsual_mode = redo_VIsual_mode;
  2286.             if (VIsual_mode == 'v')
  2287.             {
  2288.                 if (redo_VIsual_line_count <= 1)
  2289.                     curwin->w_cursor.col += redo_VIsual_col - 1;
  2290.                 else
  2291.                     curwin->w_cursor.col = redo_VIsual_col;
  2292.             }
  2293.             if (redo_VIsual_col == MAXCOL)
  2294.             {
  2295.                 curwin->w_curswant = MAXCOL;
  2296.                 coladvance(MAXCOL);
  2297.             }
  2298.             Prenum = redo_VIsual_Prenum;
  2299.         }
  2300.         else if (VIsual_active)
  2301.         {
  2302.             curbuf->b_op_start = VIsual;
  2303.             VIsual_end = curwin->w_cursor;
  2304.             if (VIsual_mode == 'V')
  2305.                 curbuf->b_op_start.col = 0;
  2306.         }
  2307.  
  2308.         if (lt(curbuf->b_op_start, curwin->w_cursor))
  2309.         {
  2310.             curbuf->b_op_end = curwin->w_cursor;
  2311.             curwin->w_cursor = curbuf->b_op_start;
  2312.         }
  2313.         else
  2314.         {
  2315.             curbuf->b_op_end = curbuf->b_op_start;
  2316.             curbuf->b_op_start = curwin->w_cursor;
  2317.         }
  2318.         op_line_count = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
  2319.  
  2320.         if (VIsual_active || redo_VIsual_busy)
  2321.         {
  2322.             if (VIsual_mode == Ctrl('V'))        /* block mode */
  2323.             {
  2324.                 colnr_t        start, end;
  2325.  
  2326.                 op_block_mode = TRUE;
  2327.                 getvcol(curwin, &(curbuf->b_op_start),
  2328.                                           &op_start_vcol, NULL, &op_end_vcol);
  2329.                 if (!redo_VIsual_busy)
  2330.                 {
  2331.                     getvcol(curwin, &(curbuf->b_op_end), &start, NULL, &end);
  2332.                     if (start < op_start_vcol)
  2333.                         op_start_vcol = start;
  2334.                     if (end > op_end_vcol)
  2335.                         op_end_vcol = end;
  2336.                 }
  2337.  
  2338.                 /* if '$' was used, get op_end_vcol from longest line */
  2339.                 if (curwin->w_curswant == MAXCOL)
  2340.                 {
  2341.                     curwin->w_cursor.col = MAXCOL;
  2342.                     op_end_vcol = 0;
  2343.                     for (curwin->w_cursor.lnum = curbuf->b_op_start.lnum;
  2344.                             curwin->w_cursor.lnum <= curbuf->b_op_end.lnum;
  2345.                             ++curwin->w_cursor.lnum)
  2346.                     {
  2347.                         getvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
  2348.                         if (end > op_end_vcol)
  2349.                             op_end_vcol = end;
  2350.                     }
  2351.                     curwin->w_cursor = curbuf->b_op_start;
  2352.                 }
  2353.                 else if (redo_VIsual_busy)
  2354.                     op_end_vcol = op_start_vcol + redo_VIsual_col - 1;
  2355.                 coladvance(op_start_vcol);
  2356.             }
  2357.  
  2358.             if (!redo_VIsual_busy)
  2359.             {
  2360.                 /*
  2361.                  * Prepare to reselect and redo Visual: this is based on the
  2362.                  * size of the Visual text
  2363.                  */
  2364.                 resel_VIsual_mode = VIsual_mode;
  2365.                 if (curwin->w_curswant == MAXCOL)
  2366.                     resel_VIsual_col = MAXCOL;
  2367.                 else if (VIsual_mode == Ctrl('V'))
  2368.                     resel_VIsual_col = op_end_vcol - op_start_vcol + 1;
  2369.                 else if (op_line_count > 1)
  2370.                     resel_VIsual_col = curbuf->b_op_end.col;
  2371.                 else
  2372.                     resel_VIsual_col = curbuf->b_op_end.col -
  2373.                                                 curbuf->b_op_start.col + 1;
  2374.                 resel_VIsual_line_count = op_line_count;
  2375.             }
  2376.                                                 /* can't redo yank and : */
  2377.             if (op_type != YANK && op_type != COLON)
  2378.             {
  2379.                 prep_redo(0L, NUL, 'v', prechar, opchars[op_type - 1]);
  2380.                 redo_VIsual_mode = resel_VIsual_mode;
  2381.                 redo_VIsual_col = resel_VIsual_col;
  2382.                 redo_VIsual_line_count = resel_VIsual_line_count;
  2383.                 redo_VIsual_Prenum = Prenum;
  2384.             }
  2385.  
  2386.             /*
  2387.              * Mincl defaults to TRUE.
  2388.              * If op_end is on a NUL (empty line) op_inclusive becomes FALSE
  2389.              * This makes "d}P" and "v}dP" work the same.
  2390.              */
  2391.             op_inclusive = TRUE;
  2392.             if (VIsual_mode == 'V')
  2393.                 op_motion_type = MLINE;
  2394.             else
  2395.             {
  2396.                 op_motion_type = MCHAR;
  2397.                 if (*ml_get_pos(&(curbuf->b_op_end)) == NUL)
  2398.                     op_inclusive = FALSE;
  2399.             }
  2400.  
  2401.             redo_VIsual_busy = FALSE;
  2402.             /*
  2403.              * Switch Visual off now, so screen updating does
  2404.              * not show inverted text when the screen is redrawn.
  2405.              * With YANK and sometimes with COLON and FILTER there is no screen
  2406.              * redraw, so it is done here to remove the inverted part.
  2407.              */
  2408.             if (!gui_yank)
  2409.             {
  2410.                 VIsual_active = FALSE;
  2411. #ifdef USE_MOUSE
  2412.                 setmouse();
  2413. #endif
  2414.                 if (p_smd)
  2415.                     clear_cmdline = TRUE;    /* unshow visual mode later */
  2416.                 if (op_type == YANK || op_type == COLON || op_type == FILTER)
  2417.                     update_curbuf(NOT_VALID);
  2418.             }
  2419.  
  2420.             /* set Prenum1 for LSHIFT and RSHIFT, e.g. "V3j2>" */
  2421.             if (Prenum == 0)
  2422.                 Prenum1 = 1L;
  2423.             else
  2424.                 Prenum1 = Prenum;
  2425.         }
  2426.  
  2427.         curwin->w_set_curswant = TRUE;
  2428.  
  2429.             /* op_empty is set when start and end are the same */
  2430.         op_empty = (op_motion_type == MCHAR && !op_inclusive &&
  2431.                                  equal(curbuf->b_op_start, curbuf->b_op_end));
  2432.  
  2433.     /*
  2434.      * If the end of an operator is in column one while op_motion_type is
  2435.      * MCHAR and op_inclusive is FALSE, we put op_end after the last character
  2436.      * in the previous line. If op_start is on or before the first non-blank
  2437.      * in the line, the operator becomes linewise (strange, but that's the way
  2438.      * vi does it).
  2439.      */
  2440.         if (op_motion_type == MCHAR && op_inclusive == FALSE &&
  2441.                            !dont_adjust_op_end && curbuf->b_op_end.col == 0 &&
  2442.                                                             op_line_count > 1)
  2443.         {
  2444.             op_end_adjusted = TRUE;        /* remember that we did this */
  2445.             --op_line_count;
  2446.             --curbuf->b_op_end.lnum;
  2447.             if (inindent(0))
  2448.                 op_motion_type = MLINE;
  2449.             else
  2450.             {
  2451.                 curbuf->b_op_end.col = STRLEN(ml_get(curbuf->b_op_end.lnum));
  2452.                 if (curbuf->b_op_end.col)
  2453.                 {
  2454.                     --curbuf->b_op_end.col;
  2455.                     op_inclusive = TRUE;
  2456.                 }
  2457.             }
  2458.         }
  2459.         else
  2460.             op_end_adjusted = FALSE;
  2461.         switch (op_type)
  2462.         {
  2463.           case LSHIFT:
  2464.           case RSHIFT:
  2465.             do_shift(op_type, TRUE, (int)Prenum1);
  2466.             break;
  2467.  
  2468.           case JOIN:
  2469.             if (op_line_count < 2)
  2470.                 op_line_count = 2;
  2471.             if (curwin->w_cursor.lnum + op_line_count - 1 >
  2472.                                                    curbuf->b_ml.ml_line_count)
  2473.                 beep_flush();
  2474.             else
  2475.             {
  2476.                 /*
  2477.                  * If the cursor position has been changed, recompute the
  2478.                  * current cursor position in the window. If it's not visible,
  2479.                  * don't keep the window updated when joining the lines.
  2480.                  */
  2481.                 if (old_cursor.lnum != curwin->w_cursor.lnum ||
  2482.                                        old_cursor.col != curwin->w_cursor.col)
  2483.                     redraw = (curs_rows() == OK);
  2484.                 else
  2485.                     redraw = TRUE;
  2486.                 do_do_join(op_line_count, TRUE, redraw);
  2487.             }
  2488.             break;
  2489.  
  2490.           case DELETE:
  2491.             if (!op_empty)
  2492.                 do_delete();
  2493.             break;
  2494.  
  2495.           case YANK:
  2496.             if (!op_empty)
  2497.                 (void)do_yank(FALSE, !gui_yank);
  2498.             break;
  2499.  
  2500.           case CHANGE:
  2501.             *command_busy = do_change();    /* will set op_type to NOP */
  2502.             break;
  2503.  
  2504.           case FILTER:
  2505.             if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
  2506.                 AppendToRedobuff((char_u *)"!\r");    /* use any last used !cmd */
  2507.             else
  2508.                 bangredo = TRUE;    /* do_bang() will put cmd in redo buffer */
  2509.  
  2510.           case INDENT:
  2511.           case COLON:
  2512.  
  2513. #if defined(LISPINDENT) || defined(CINDENT)
  2514.             /*
  2515.              * If 'equalprg' is empty, do the indenting internally.
  2516.              */
  2517.             if (op_type == INDENT && *p_ep == NUL)
  2518.             {
  2519. # ifdef LISPINDENT
  2520.                 if (curbuf->b_p_lisp)
  2521.                 {
  2522.                     do_reindent(get_lisp_indent);
  2523.                     break;
  2524.                 }
  2525. # endif
  2526. # ifdef CINDENT
  2527.                 do_reindent(get_c_indent);
  2528.                 break;
  2529. # endif
  2530.             }
  2531. #endif /* defined(LISPINDENT) || defined(CINDENT) */
  2532.  
  2533. dofilter:
  2534.             if (VIsual_was_active)
  2535.                 sprintf((char *)IObuff, ":'<,'>");
  2536.             else
  2537.                 sprintf((char *)IObuff, ":%ld,%ld",
  2538.                         (long)curbuf->b_op_start.lnum,
  2539.                         (long)curbuf->b_op_end.lnum);
  2540.             stuffReadbuff(IObuff);
  2541.             if (op_type != COLON)
  2542.                 stuffReadbuff((char_u *)"!");
  2543.             if (op_type == INDENT)
  2544.             {
  2545. #ifndef CINDENT
  2546.                 if (*p_ep == NUL)
  2547.                     stuffReadbuff((char_u *)"indent");
  2548.                 else
  2549. #endif
  2550.                     stuffReadbuff(p_ep);
  2551.                 stuffReadbuff((char_u *)"\n");
  2552.             }
  2553.             else if (op_type == FORMAT || op_type == GFORMAT)
  2554.             {
  2555.                 if (*p_fp == NUL)
  2556.                     stuffReadbuff((char_u *)"fmt");
  2557.                 else
  2558.                     stuffReadbuff(p_fp);
  2559.                 stuffReadbuff((char_u *)"\n");
  2560.             }
  2561.                 /*    do_cmdline() does the rest */
  2562.             break;
  2563.  
  2564.           case TILDE:
  2565.           case UPPER:
  2566.           case LOWER:
  2567.             if (!op_empty)
  2568.                 do_tilde();
  2569.             break;
  2570.  
  2571.           case FORMAT:
  2572.           case GFORMAT:
  2573.             if (*p_fp != NUL)
  2574.                 goto dofilter;        /* use external command */
  2575.             do_format();            /* use internal function */
  2576.             break;
  2577.  
  2578.           default:
  2579.             clearopbeep();
  2580.         }
  2581.         prechar = NUL;
  2582.         if (!gui_yank)
  2583.         {
  2584.             /*
  2585.              * if 'sol' not set, go back to old column for some commands
  2586.              */
  2587.             if (!p_sol && op_motion_type == MLINE && (op_type == LSHIFT ||
  2588.                                     op_type == RSHIFT || op_type == DELETE))
  2589.                 coladvance(curwin->w_curswant = old_col);
  2590.             op_type = NOP;
  2591.         }
  2592.         else
  2593.             curwin->w_cursor = old_cursor;
  2594.         op_block_mode = FALSE;
  2595.         yankbuffer = 0;
  2596.     }
  2597. }
  2598.  
  2599. #ifdef USE_MOUSE
  2600. /*
  2601.  * Do the appropriate action for the current mouse click in the current mode.
  2602.  *
  2603.  * Normal Mode:
  2604.  * event         modi-  position      visual       change    action
  2605.  *               fier   cursor                         window
  2606.  * left press      -        yes            end                yes
  2607.  * left press      C        yes            end                yes        "^]" (2)
  2608.  * left press      S        yes            end                yes        "*" (2)
  2609.  * left drag      -        yes        start if moved      no
  2610.  * left relse      -        yes        start if moved        no
  2611.  * middle press      -      yes         if not active        no        put register
  2612.  * middle press      -     yes         if active            no        yank and put
  2613.  * right press      -        yes        start or extend        yes
  2614.  * right press      S        yes        no change              yes        "#" (2)
  2615.  * right drag      -        yes        extend                no
  2616.  * right relse      -        yes        extend                no
  2617.  *
  2618.  * Insert or Replace Mode:
  2619.  * event         modi-  position      visual       change    action
  2620.  *               fier   cursor                         window
  2621.  * left press      -        yes        (cannot be active)    yes
  2622.  * left press      C        yes        (cannot be active)    yes        "CTRL-O^]" (2)
  2623.  * left press      S        yes        (cannot be active)    yes        "CTRL-O*" (2)
  2624.  * left drag      -        yes        start or extend (1)    no        CTRL-O (1)
  2625.  * left relse      -        yes        start or extend (1)    no        CTRL-O (1)
  2626.  * middle press      -     no          (cannot be active)    no        put register
  2627.  * right press      -        yes        start or extend        yes        CTRL-O
  2628.  * right press      S        yes        (cannot be active)    yes        "CTRL-O#" (2)
  2629.  *
  2630.  * (1) only if mouse pointer moved since press
  2631.  * (2) only if click is in same buffer
  2632.  *
  2633.  * Return TRUE if start_arrow() should be called for edit mode.
  2634.  */
  2635.     int
  2636. do_mouse(c, dir, count, fix_indent)
  2637.     int        c;                /* K_LEFTMOUSE, etc */
  2638.     int        dir;            /* Direction to 'put' if necessary */
  2639.     long    count;
  2640.     int        fix_indent;        /* Do we fix indent for 'put' if necessary? */
  2641. {
  2642.     static int    ignore_drag_release = FALSE;
  2643.     static FPOS    orig_cursor;
  2644.     static int    do_always = FALSE;        /* ignore 'mouse' setting next time */
  2645.     static int    got_click = FALSE;        /* got a click some time back */
  2646.  
  2647.     int        which_button;        /* MOUSE_LEFT, _MIDDLE or _RIGHT */
  2648.     int        is_click;            /* If FALSE it's a drag or release event */
  2649.     int        is_drag;            /* If TRUE it's a drag event */
  2650.     int        jump_flags = 0;        /* flags for jump_to_mouse() */
  2651.     FPOS    start_visual;
  2652.     FPOS    end_visual;
  2653.     BUF        *save_buffer;
  2654.     int        diff;
  2655.     int        moved;                /* Has cursor moved? */
  2656.     int        c1, c2;
  2657.     int        VIsual_was_active = VIsual_active;
  2658.  
  2659.     /*
  2660.      * When GUI is active, always recognize mouse events, otherwise:
  2661.      * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
  2662.      * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
  2663.      * - For command line and insert mode 'mouse' is checked before calling
  2664.      *   do_mouse().
  2665.      */
  2666.     if (do_always)
  2667.         do_always = FALSE;
  2668.     else
  2669. #ifdef USE_GUI
  2670.         if (!gui.in_use)
  2671. #endif
  2672.         {
  2673.             if (VIsual_active)
  2674.             {
  2675.                 if (!mouse_has(MOUSE_VISUAL))
  2676.                     return FALSE;
  2677.             }
  2678.             else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
  2679.                 return FALSE;
  2680.         }
  2681.  
  2682.     which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
  2683.  
  2684.     /*
  2685.      * Ignore drag and release events if we didn't get a click.
  2686.      */
  2687.     if (is_click)
  2688.         got_click = TRUE;
  2689.     else
  2690.     {
  2691.         if (!got_click)                    /* didn't get click, ignore */
  2692.             return FALSE;
  2693.         if (!is_drag)                    /* release, reset got_click */
  2694.             got_click = FALSE;
  2695.     }
  2696.  
  2697.     /*
  2698.      * ALT is currently ignored
  2699.      */
  2700.     if ((mod_mask & MOD_MASK_ALT))
  2701.         return FALSE;
  2702.  
  2703.     /*
  2704.      * CTRL right mouse button does CTRL-T
  2705.      */
  2706.     if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
  2707.     {
  2708.         if (State & INSERT)
  2709.             stuffcharReadbuff(Ctrl('O'));
  2710.         stuffcharReadbuff(Ctrl('T'));
  2711.         got_click = FALSE;                /* ignore drag&release now */
  2712.         return FALSE;
  2713.     }
  2714.  
  2715.     /*
  2716.      * CTRL only works with left mouse button
  2717.      */
  2718.     if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
  2719.         return FALSE;
  2720.  
  2721.     /*
  2722.      * When a modifier is down, ignore drag and release events, as well as
  2723.      * multiple clicks and the middle mouse button. 
  2724.      */
  2725.     if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT)) &&
  2726.                             (!is_click || (mod_mask & MOD_MASK_MULTI_CLICK) ||
  2727.                                                 which_button == MOUSE_MIDDLE))
  2728.         return FALSE;
  2729.  
  2730.     /*
  2731.      * If the button press was used as the movement command for an operator
  2732.      * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
  2733.      * drag/release events.
  2734.      */
  2735.     if (!is_click && (ignore_drag_release || which_button == MOUSE_MIDDLE))
  2736.         return FALSE;
  2737.  
  2738.     /*
  2739.      * Middle mouse button does a 'put' of the selected text
  2740.      */
  2741.     if (which_button == MOUSE_MIDDLE)
  2742.     {
  2743.         if (State == NORMAL)
  2744.         {
  2745.             /*
  2746.              * If an operator was pending, we don't know what the user wanted
  2747.              * to do. Go back to normal mode: Clear the operator and beep().
  2748.              */
  2749.             if (op_type != NOP)
  2750.             {
  2751.                 clearopbeep();
  2752.                 return FALSE;
  2753.             }
  2754.  
  2755.             /*
  2756.              * If visual was active, yank the highlighted text and put it
  2757.              * before the mouse pointer position.
  2758.              */
  2759.             if (VIsual_active)
  2760.             {
  2761.                 stuffcharReadbuff('y');
  2762.                 stuffcharReadbuff(K_MIDDLEMOUSE);
  2763.                 do_always = TRUE;        /* ignore 'mouse' setting next time */
  2764.                 return FALSE;
  2765.             }
  2766.             /*
  2767.              * The rest is below jump_to_mouse()
  2768.              */
  2769.         }
  2770.  
  2771.         /*
  2772.          * Middle click in insert mode doesn't move the mouse, just insert the
  2773.          * contents of a register.  '.' register is special, can't insert that
  2774.          * with do_put().
  2775.          */
  2776.         else if (State & INSERT)
  2777.         {
  2778.             if (yankbuffer == '.')
  2779.                 insertbuf(yankbuffer);
  2780.             else
  2781.             {
  2782. #ifdef USE_GUI
  2783.                 if (gui.in_use && yankbuffer == 0)
  2784.                     yankbuffer = '*';
  2785. #endif
  2786.                 do_put(BACKWARD, 1L, fix_indent);
  2787.  
  2788.                 /* Put cursor after the end of the just pasted text. */
  2789.                 curwin->w_cursor = curbuf->b_op_end;
  2790.                 if (gchar_cursor() != NUL)
  2791.                     ++curwin->w_cursor.col;
  2792.  
  2793.                 /* Repeat it with CTRL-R x, not exactly the same, but mostly
  2794.                  * works fine. */
  2795.                 AppendCharToRedobuff(Ctrl('R'));
  2796.                 if (yankbuffer == 0)
  2797.                     AppendCharToRedobuff('"');
  2798.                 else
  2799.                     AppendCharToRedobuff(yankbuffer);
  2800.             }
  2801.             return FALSE;
  2802.         }
  2803.         else
  2804.             return FALSE;
  2805.     }
  2806.  
  2807.     if (!is_click)
  2808.         jump_flags |= MOUSE_FOCUS;
  2809.  
  2810.     start_visual.lnum = 0;
  2811.  
  2812.     if ((State & (NORMAL | INSERT)) &&
  2813.                                !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
  2814.     {
  2815.         if (which_button == MOUSE_LEFT)
  2816.         {
  2817.             if (is_click)
  2818.             {
  2819.                 if (VIsual_active)
  2820.                 {
  2821.                     end_visual_mode();
  2822.                     update_curbuf(NOT_VALID);
  2823.                 }
  2824.             }
  2825.             else
  2826.                 jump_flags |= MOUSE_MAY_VIS;
  2827.         }
  2828.         else if (which_button == MOUSE_RIGHT)
  2829.         {
  2830.             if (is_click && VIsual_active)
  2831.             {
  2832.                 /*
  2833.                  * Remember the start and end of visual before moving the
  2834.                  * cursor.
  2835.                  */
  2836.                 if (lt(curwin->w_cursor, VIsual))
  2837.                 {
  2838.                     start_visual = curwin->w_cursor;
  2839.                     end_visual = VIsual;
  2840.                 }
  2841.                 else
  2842.                 {
  2843.                     start_visual = VIsual;
  2844.                     end_visual = curwin->w_cursor;
  2845.                 }
  2846.             }
  2847.             jump_flags |= MOUSE_MAY_VIS;
  2848.         }
  2849.     }
  2850.  
  2851.     if (!is_drag)
  2852.     {
  2853.         /*
  2854.          * If an operator is pending, ignore all drags and releases until the
  2855.          * next mouse click.
  2856.          */
  2857.         ignore_drag_release = (op_type != NOP);
  2858.     }
  2859.  
  2860.     /*
  2861.      * Jump!
  2862.      */
  2863.     if (!is_click)
  2864.         jump_flags |= MOUSE_DID_MOVE;
  2865.     save_buffer = curbuf;
  2866.     moved = (jump_to_mouse(jump_flags) & CURSOR_MOVED);
  2867.  
  2868.     /* When jumping to another buffer, stop visual mode */
  2869.     if (curbuf != save_buffer && VIsual_active)
  2870.     {
  2871.         end_visual_mode();
  2872.         update_curbuf(NOT_VALID);        /* delete the inversion */
  2873.     }
  2874.     else if (start_visual.lnum)        /* right click in visual mode */
  2875.     {
  2876.         /*
  2877.          * If the click is before the start of visual, change the start.  If
  2878.          * the click is after the end of visual, change the end.  If the click
  2879.          * is inside the visual, change the closest side.
  2880.          */
  2881.         if (lt(curwin->w_cursor, start_visual))
  2882.             VIsual = end_visual;
  2883.         else if (lt(end_visual, curwin->w_cursor))
  2884.             VIsual = start_visual;
  2885.         else
  2886.         {
  2887.             /* In the same line, compare column number */
  2888.             if (end_visual.lnum == start_visual.lnum)
  2889.             {
  2890.                 if (curwin->w_cursor.col - start_visual.col >
  2891.                                 end_visual.col - curwin->w_cursor.col)
  2892.                     VIsual = start_visual;
  2893.                 else
  2894.                     VIsual = end_visual;
  2895.             }
  2896.  
  2897.             /* In different lines, compare line number */
  2898.             else
  2899.             {
  2900.                 diff = (curwin->w_cursor.lnum - start_visual.lnum) -
  2901.                             (end_visual.lnum - curwin->w_cursor.lnum);
  2902.  
  2903.                 if (diff > 0)            /* closest to end */
  2904.                     VIsual = start_visual;
  2905.                 else if (diff < 0)        /* closest to start */
  2906.                     VIsual = end_visual;
  2907.                 else                    /* in the middle line */
  2908.                 {
  2909.                     if (curwin->w_cursor.col <
  2910.                                     (start_visual.col + end_visual.col) / 2)
  2911.                         VIsual = end_visual;
  2912.                     else
  2913.                         VIsual = start_visual;
  2914.                 }
  2915.             }
  2916.         }
  2917.     }
  2918.     /*
  2919.      * If Visual mode started in insert mode, execute "CTRL-O"
  2920.      */
  2921.     else if ((State & INSERT) && VIsual_active)
  2922.         stuffcharReadbuff(Ctrl('O'));
  2923.     /*
  2924.      * If cursor has moved, need to update Cline_row
  2925.      */
  2926.     else if (moved)
  2927.         cursupdate();
  2928.  
  2929.     /*
  2930.      * Middle mouse click: Put text before cursor.
  2931.      */
  2932.     if (which_button == MOUSE_MIDDLE)
  2933.     {
  2934. #ifdef USE_GUI
  2935.         if (gui.in_use && yankbuffer == 0)
  2936.             yankbuffer = '*';
  2937. #endif
  2938.         if (yank_buffer_mline())
  2939.         {
  2940.             if (mouse_past_bottom)
  2941.                 dir = FORWARD;
  2942.         }
  2943.         else if (mouse_past_eol)
  2944.             dir = FORWARD;
  2945.  
  2946.         if (fix_indent)
  2947.         {
  2948.             c1 = (dir == BACKWARD) ? '[' : ']';
  2949.             c2 = 'p';
  2950.         }
  2951.         else
  2952.         {
  2953.             c1 = (dir == FORWARD) ? 'p' : 'P';
  2954.             c2 = NUL;
  2955.         }
  2956.         prep_redo(Prenum, NUL, c1, c2, NUL);
  2957.         /*
  2958.          * Remember where the paste started, so in edit() Insstart can be set
  2959.          * to this position
  2960.          */
  2961.         if (restart_edit)
  2962.             where_paste_started = curwin->w_cursor;
  2963.         do_put(dir, count, fix_indent);
  2964.  
  2965.         /* Put cursor at the end of the just pasted text. */
  2966.         curwin->w_cursor = curbuf->b_op_end;
  2967.         if (restart_edit && gchar_cursor() != NUL)
  2968.             ++curwin->w_cursor.col;            /* put cursor after the text */
  2969.     }
  2970.  
  2971.     /*
  2972.      * Ctrl-Mouse click jumps to the tag under the mouse pointer
  2973.      */
  2974.     else if ((mod_mask & MOD_MASK_CTRL))
  2975.     {
  2976.         if (State & INSERT)
  2977.             stuffcharReadbuff(Ctrl('O'));
  2978.         stuffcharReadbuff(Ctrl(']'));
  2979.         ignore_drag_release = TRUE;        /* ignore drag and release now */
  2980.     }
  2981.  
  2982.     /*
  2983.      * Shift-Mouse click searches for the next occurrence of the word under
  2984.      * the mouse pointer
  2985.      */
  2986.     else if ((mod_mask & MOD_MASK_SHIFT))
  2987.     {
  2988.         if (State & INSERT)
  2989.             stuffcharReadbuff(Ctrl('O'));
  2990.         if (which_button == MOUSE_LEFT)
  2991.             stuffcharReadbuff('*');
  2992.         else    /* MOUSE_RIGHT */
  2993.             stuffcharReadbuff('#');
  2994.     }
  2995.  
  2996.     /* Handle double clicks */
  2997.     else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT)))
  2998.     {
  2999.         if (is_click || !VIsual_active)
  3000.         {
  3001.             if (VIsual_active)
  3002.                 orig_cursor = VIsual;
  3003.             else
  3004.             {
  3005.                 start_visual_highlight();
  3006.                 VIsual = curwin->w_cursor;
  3007.                 orig_cursor = VIsual;
  3008.                 VIsual_active = TRUE;
  3009. #ifdef USE_MOUSE
  3010.                 setmouse();
  3011. #endif
  3012.                 if (p_smd)
  3013.                     redraw_cmdline = TRUE;    /* show visual mode later */
  3014.             }
  3015.             if (mod_mask & MOD_MASK_2CLICK)
  3016.                 VIsual_mode = 'v';
  3017.             else if (mod_mask & MOD_MASK_3CLICK)
  3018.                 VIsual_mode = 'V';
  3019.             else if (mod_mask & MOD_MASK_4CLICK)
  3020.                 VIsual_mode = Ctrl('V');
  3021.         }
  3022.         if (mod_mask & MOD_MASK_2CLICK)
  3023.         {
  3024.             if (lt(curwin->w_cursor, orig_cursor))
  3025.             {
  3026.                 find_start_of_word(&curwin->w_cursor);
  3027.                 find_end_of_word(&VIsual);
  3028.             }
  3029.             else
  3030.             {
  3031.                 find_start_of_word(&VIsual);
  3032.                 find_end_of_word(&curwin->w_cursor);
  3033.             }
  3034.             curwin->w_set_curswant = TRUE;
  3035.         }
  3036.         if (is_click)
  3037.         {
  3038.             curs_columns(TRUE);                /* recompute w_virtcol */
  3039.             update_curbuf(NOT_VALID);        /* update the inversion */
  3040.         }
  3041.     }
  3042.     else if (VIsual_active && VIsual_was_active != VIsual_active)
  3043.         VIsual_mode = 'v';
  3044.  
  3045.     return moved;
  3046. }
  3047.  
  3048.     static void
  3049. find_start_of_word(pos)
  3050.     FPOS    *pos;
  3051. {
  3052.     char_u    *ptr;
  3053.     int        cclass;
  3054.  
  3055.     ptr = ml_get(pos->lnum);
  3056.     cclass = get_mouse_class(ptr[pos->col]);
  3057.  
  3058.     /* Can't test pos->col >= 0 because pos->col is unsigned */
  3059.     while (pos->col > 0 && get_mouse_class(ptr[pos->col]) == cclass)
  3060.         pos->col--;
  3061.     if (pos->col != 0 || get_mouse_class(ptr[0]) != cclass)
  3062.         pos->col++;
  3063. }
  3064.  
  3065.     static void
  3066. find_end_of_word(pos)
  3067.     FPOS    *pos;
  3068. {
  3069.     char_u    *ptr;
  3070.     int        cclass;
  3071.  
  3072.     ptr = ml_get(pos->lnum);
  3073.     cclass = get_mouse_class(ptr[pos->col]);
  3074.     while (ptr[pos->col] && get_mouse_class(ptr[pos->col]) == cclass)
  3075.         pos->col++;
  3076.     pos->col--;
  3077. }
  3078.  
  3079.     static int
  3080. get_mouse_class(c)
  3081.     int        c;
  3082. {
  3083.     if (c == ' ' || c == '\t')
  3084.         return ' ';
  3085.  
  3086.     if (isidchar(c))
  3087.         return 'a';
  3088.  
  3089.     /*
  3090.      * There are a few special cases where we want certain combinations of
  3091.      * characters to be considered as a single word.  These are things like
  3092.      * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc.  Otherwise, each
  3093.      * character is in it's own class.
  3094.      */
  3095.     if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
  3096.         return '=';
  3097.     return c;
  3098. }
  3099. #endif /* USE_MOUSE */
  3100.  
  3101. /*
  3102.  * start highlighting for visual mode
  3103.  */
  3104.     void
  3105. start_visual_highlight()
  3106. {
  3107.     static int        didwarn = FALSE;        /* warned for broken inversion */
  3108.  
  3109.     if (!didwarn && set_highlight('v') == FAIL)/* cannot highlight */
  3110.     {
  3111.         EMSG("Warning: terminal cannot highlight");
  3112.         didwarn = TRUE;
  3113.     }
  3114. }
  3115.  
  3116. /*
  3117.  * End visual mode.  If we are using the GUI, and autoselect is set, then
  3118.  * remember what was selected in case we need to paste it somewhere while we
  3119.  * still own the selection.  This function should ALWAYS be called to end
  3120.  * visual mode.
  3121.  */
  3122.     void
  3123. end_visual_mode()
  3124. {
  3125. #ifdef USE_GUI
  3126.     if (gui.in_use)
  3127.         gui_auto_select();
  3128. #endif
  3129.     VIsual_active = FALSE;
  3130. #ifdef USE_MOUSE
  3131.     setmouse();
  3132. #endif
  3133.     VIsual_end = curwin->w_cursor;        /* remember for '> mark */
  3134.     if (p_smd)
  3135.         clear_cmdline = TRUE;            /* unshow visual mode later */
  3136. }
  3137.  
  3138. /*
  3139.  * Find the identifier under or to the right of the cursor.  If none is
  3140.  * found and find_type has FIND_STRING, then find any non-white string.  The
  3141.  * length of the string is returned, or zero if no string is found.  If a
  3142.  * string is found, a pointer to the string is put in *string, but note that
  3143.  * the caller must use the length returned as this string may not be NUL
  3144.  * terminated.
  3145.  */
  3146.     int
  3147. find_ident_under_cursor(string, find_type)
  3148.     char_u    **string;
  3149.     int        find_type;
  3150. {
  3151.     char_u    *ptr;
  3152.     int        col = 0;        /* init to shut up GCC */
  3153.     int        i;
  3154.  
  3155.     /*
  3156.      * if i == 0: try to find an identifier
  3157.      * if i == 1: try to find any string
  3158.      */
  3159.     ptr = ml_get_curline();
  3160.     for (i = (find_type & FIND_IDENT) ? 0 : 1;    i < 2; ++i)
  3161.     {
  3162.         /*
  3163.          * skip to start of identifier/string
  3164.          */
  3165.         col = curwin->w_cursor.col;
  3166.         while (ptr[col] != NUL &&
  3167.                     (i == 0 ? !iswordchar(ptr[col]) : vim_iswhite(ptr[col])))
  3168.             ++col;
  3169.  
  3170.         /*
  3171.          * Back up to start of identifier/string. This doesn't match the
  3172.          * real vi but I like it a little better and it shouldn't bother
  3173.          * anyone.
  3174.          * When FIND_IDENT isn't defined, we backup until a blank.
  3175.          */
  3176.         while (col > 0 && (i == 0 ? iswordchar(ptr[col - 1]) :
  3177.                     (!vim_iswhite(ptr[col - 1]) &&
  3178.                    (!(find_type & FIND_IDENT) || !iswordchar(ptr[col - 1])))))
  3179.             --col;
  3180.  
  3181.         /*
  3182.          * if we don't want just any old string, or we've found an identifier,
  3183.          * stop searching.
  3184.          */
  3185.         if (!(find_type & FIND_STRING) || iswordchar(ptr[col]))
  3186.             break;
  3187.     }
  3188.     /*
  3189.      * didn't find an identifier or string
  3190.      */
  3191.     if (ptr[col] == NUL || (!iswordchar(ptr[col]) && i == 0))
  3192.     {
  3193.         if (find_type & FIND_STRING)
  3194.             EMSG("No string under cursor");
  3195.         else
  3196.             EMSG("No identifier under cursor");
  3197.         return 0;
  3198.     }
  3199.     ptr += col;
  3200.     *string = ptr;
  3201.     col = 0;
  3202.     while (i == 0 ? iswordchar(*ptr) : (*ptr != NUL && !vim_iswhite(*ptr)))
  3203.     {
  3204.         ++ptr;
  3205.         ++col;
  3206.     }
  3207.     return col;
  3208. }
  3209.  
  3210.     static void
  3211. prep_redo(num, pre_char, cmd, c, nchar)
  3212.     long     num;
  3213.     int        pre_char;
  3214.     int        cmd;
  3215.     int        c;
  3216.     int        nchar;
  3217. {
  3218.     ResetRedobuff();
  3219.     if (yankbuffer != 0)    /* yank from specified buffer */
  3220.     {
  3221.         AppendCharToRedobuff('\"');
  3222.         AppendCharToRedobuff(yankbuffer);
  3223.     }
  3224.     if (num)
  3225.         AppendNumberToRedobuff(num);
  3226.     if (pre_char != NUL)
  3227.         AppendCharToRedobuff(pre_char);
  3228.     AppendCharToRedobuff(cmd);
  3229.     if (c != NUL)
  3230.         AppendCharToRedobuff(c);
  3231.     if (nchar != NUL)
  3232.         AppendCharToRedobuff(nchar);
  3233. }
  3234.  
  3235. /*
  3236.  * check for operator active and clear it
  3237.  *
  3238.  * return TRUE if operator was active
  3239.  */
  3240.     static int
  3241. checkclearop()
  3242. {
  3243.     if (op_type == NOP)
  3244.         return (FALSE);
  3245.     clearopbeep();
  3246.     return (TRUE);
  3247. }
  3248.  
  3249. /*
  3250.  * check for operator or Visual active and clear it
  3251.  *
  3252.  * return TRUE if operator was active
  3253.  */
  3254.     static int
  3255. checkclearopq()
  3256. {
  3257.     if (op_type == NOP && !VIsual_active)
  3258.         return (FALSE);
  3259.     clearopbeep();
  3260.     return (TRUE);
  3261. }
  3262.  
  3263.     static void
  3264. clearop()
  3265. {
  3266.     op_type = NOP;
  3267.     yankbuffer = 0;
  3268.     prechar = NUL;
  3269. }
  3270.  
  3271.     static void
  3272. clearopbeep()
  3273. {
  3274.     clearop();
  3275.     beep_flush();
  3276. }
  3277.  
  3278. /*
  3279.  * Routines for displaying a partly typed command
  3280.  */
  3281.  
  3282. static char_u    showcmd_buf[SHOWCMD_COLS + 1];
  3283. static char_u    old_showcmd_buf[SHOWCMD_COLS + 1];    /* For push_showcmd() */
  3284. static int        is_showcmd_clear = TRUE;
  3285.  
  3286. static void display_showcmd __ARGS((void));
  3287.  
  3288.     void
  3289. clear_showcmd()
  3290. {
  3291.     if (!p_sc)
  3292.         return;
  3293.  
  3294.     showcmd_buf[0] = NUL;
  3295.  
  3296.     /*
  3297.      * Don't actually display something if there is nothing to clear.
  3298.      */
  3299.     if (is_showcmd_clear)
  3300.         return;
  3301.  
  3302.     display_showcmd();
  3303. }
  3304.  
  3305. /*
  3306.  * Add 'c' to string of shown command chars.
  3307.  * Return TRUE if setcursor() has been called.
  3308.  */
  3309.     int
  3310. add_to_showcmd(c, display_always)
  3311.     int     c;
  3312.     int        display_always;
  3313. {
  3314.     char_u    *p;
  3315.     int        old_len;
  3316.     int        extra_len;
  3317.     int        overflow;
  3318.  
  3319.     if (!p_sc)
  3320.         return FALSE;
  3321.  
  3322.     p = transchar(c);
  3323.     old_len = STRLEN(showcmd_buf);
  3324.     extra_len = STRLEN(p);
  3325.     overflow = old_len + extra_len - SHOWCMD_COLS;
  3326.     if (overflow > 0)
  3327.         STRCPY(showcmd_buf, showcmd_buf + overflow);
  3328.     STRCAT(showcmd_buf, p);
  3329.  
  3330.     if (!display_always && char_avail())
  3331.         return FALSE;
  3332.  
  3333.     display_showcmd();
  3334.  
  3335.     return TRUE;
  3336. }
  3337.  
  3338. /*
  3339.  * Delete 'len' characters from the end of the shown command.
  3340.  */
  3341.     static void
  3342. del_from_showcmd(len)
  3343.     int     len;
  3344. {
  3345.     int        old_len;
  3346.  
  3347.     if (!p_sc)
  3348.         return;
  3349.  
  3350.     old_len = STRLEN(showcmd_buf);
  3351.     if (len > old_len)
  3352.         len = old_len;
  3353.     showcmd_buf[old_len - len] = NUL;
  3354.  
  3355.     if (!char_avail())
  3356.         display_showcmd();
  3357. }
  3358.  
  3359.     void
  3360. push_showcmd()
  3361. {
  3362.     if (p_sc)
  3363.         STRCPY(old_showcmd_buf, showcmd_buf);
  3364. }
  3365.  
  3366.     void
  3367. pop_showcmd()
  3368. {
  3369.     if (!p_sc)
  3370.         return;
  3371.  
  3372.     STRCPY(showcmd_buf, old_showcmd_buf);
  3373.  
  3374.     display_showcmd();
  3375. }
  3376.  
  3377.     static void
  3378. display_showcmd()
  3379. {
  3380.     int        len;
  3381.  
  3382.     cursor_off();
  3383.  
  3384.     len = STRLEN(showcmd_buf);
  3385.     if (len == 0)
  3386.         is_showcmd_clear = TRUE;
  3387.     else
  3388.     {
  3389.         screen_msg(showcmd_buf, (int)Rows - 1, sc_col);
  3390.         is_showcmd_clear = FALSE;
  3391.     }
  3392.  
  3393.     /*
  3394.      * clear the rest of an old message by outputing up to SHOWCMD_COLS spaces
  3395.      */
  3396.     screen_msg((char_u *)"          " + len, (int)Rows - 1, sc_col + len);
  3397.  
  3398.     setcursor();            /* put cursor back where it belongs */
  3399. }
  3400.  
  3401. /*
  3402.  * Implementation of "gd" and "gD" command.
  3403.  */
  3404.     static void
  3405. do_gd(nchar)
  3406.     int        nchar;
  3407. {
  3408.     int            len;
  3409.     char_u        *pat;
  3410.     FPOS        old_pos;
  3411.     int            t;
  3412.     int            save_p_ws;
  3413.     int            save_p_scs;
  3414.     char_u        *ptr;
  3415.  
  3416.     if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 ||
  3417.                                                (pat = alloc(len + 5)) == NULL)
  3418.     {
  3419.         clearopbeep();
  3420.         return;
  3421.     }
  3422.     sprintf((char *)pat, iswordchar(*ptr) ? "\\<%.*s\\>" :
  3423.             "%.*s", len, ptr);
  3424.     old_pos = curwin->w_cursor;
  3425.     save_p_ws = p_ws;
  3426.     save_p_scs = p_scs;
  3427.     p_ws = FALSE;        /* don't wrap around end of file now */
  3428.     p_scs = FALSE;        /* don't switch ignorecase off now */
  3429.     fo_do_comments = TRUE;
  3430.  
  3431.     /*
  3432.      * Search back for the end of the previous function.
  3433.      * If this fails, and with "gD", go to line 1.
  3434.      * Search forward for the identifier, ignore comment lines.
  3435.      */
  3436.     if (nchar == 'D' || !findpar(BACKWARD, 1L, '}', FALSE))
  3437.     {
  3438.         setpcmark();                    /* Set in findpar() otherwise */
  3439.         curwin->w_cursor.lnum = 1;
  3440.     }
  3441.  
  3442.     while ((t = searchit(&curwin->w_cursor, FORWARD, pat, 1L, 0, RE_LAST))
  3443.                 == OK &&
  3444.             get_leader_len(ml_get_curline(), NULL) &&
  3445.             old_pos.lnum > curwin->w_cursor.lnum)
  3446.         ++curwin->w_cursor.lnum;
  3447.     if (t == FAIL || old_pos.lnum <= curwin->w_cursor.lnum)
  3448.     {
  3449.         clearopbeep();
  3450.         curwin->w_cursor = old_pos;
  3451.     }
  3452.     else
  3453.         curwin->w_set_curswant = TRUE;
  3454.  
  3455.     vim_free(pat);
  3456.     p_ws = save_p_ws;
  3457.     p_scs = save_p_scs;
  3458.     fo_do_comments = FALSE;
  3459. }
  3460.